QFinance.AppMobile = Ext.extend(Object, {
	// Localization
	newExpenseAnnotationText: 'New expense annotation',
	requiredText: 'Please enter the information above.',
	accountText: 'Account',
	dateText: 'Date',
	descriptionText: 'Description',
	amountText: 'Amount',
	destinationText: 'Destination',
	categoryText: 'Category',
	resetText: 'Reset',
	addText: 'Add',
	fillRequiredText: 'Please fill required fields.',
	internalServerErrorText: 'Internal server error.',
	
	show: function() {
		Ext.regModel('TransactionAnnotation', {
            fields: [{
				name: 'date',		
			    type: 'date',	
			    dateFormat: "c"
			},{
				name: 'description'
			},,{
				name: 'amount',	
				type: 'float'
			},{
				name: 'sourceAccountID',
				type: 'int',
				useNull: true
			},{
				name: 'destinationAccountID',
				type: 'int',
				useNull: true
			},{
				name: 'categoryID', 
				type: 'int',
				useNull: true
			}]
        });
    	
    	var privateAccountsStore = new Ext.data.JsonStore({
    		fields: [
         		    {
         		    	name: 'id',
         		    	type: 'int'
         		    },
         		    {
         		    	name: 'accountName'	    		    
         		    },
         		    {
         		    	name: 'accountType'
         		    }
         		]
         });
        
    	var accountsStore = new Ext.data.JsonStore({
    		fields: [
         		    {
         		    	name: 'id',
         		    	type: 'int'
         		    },
         		    {
         		    	name: 'accountName'	    		    
         		    },
         		    {
         		    	name: 'accountType'
         		    }
         		]
         });
    	
    	var categoriesStore = new Ext.data.JsonStore({
    		fields: [
         		    {
         		    	name: 'id',
         		    	type: 'int'
         		    },
         		    {
         		    	name: 'categoryName'	    		    
         		    }
         		]
         });
       
        var formBase = {
            scroll: 'vertical',
            items: [
                {
                    xtype: 'fieldset',
                    title: this.newExpenseAnnotationText,
                    instructions: this.requiredText,
                    defaults: {                        
                        labelAlign: 'left',
                        labelWidth: '40%'
                    },
                    items: [ this.sourceAccountCombo = new Ext.form.Select({
                        xtype: 'selectfield',
                        name : 'sourceAccountID',
                        label: this.accountText,
                        valueField : 'id',
                        displayField : 'accountName',
                        store : privateAccountsStore,
                        required: true
                    }),{
                    	xtype: 'datepickerfield',
                    	name: 'date',
                    	label: this.dateText,
                    	value: new Date(),
                    	required: true
                    },{
                        xtype: 'textfield',
                        name : 'description',
                        label: this.descriptionText,
                        useClearIcon: true,
                        autoCapitalize : false,
                        required: true
                    },{
                    	xtype: 'numberfield',
                        name: 'amount',
                        label: this.amountText,
                        required: true,
                        decimalSeparator: QFinance.decimalSeparator
                    }, this.destinationAccountCombo = new Ext.form.Select({
                        xtype: 'selectfield',
                        name : 'destinationAccountID',
                        label: this.destinationText,
                        valueField : 'id',
                        displayField : 'accountName',
                        store : accountsStore,
                        required: false
                    }), this.categoryCombo = new Ext.form.Select({
                        xtype: 'selectfield',
                        name : 'categoryID',
                        label: this.categoryText,
                        valueField : 'id',
                        displayField : 'categoryName',
                        store : categoriesStore,
                        required: false
                    })]
                }],
        
            dockedItems: [
                {
                    xtype: 'toolbar',
                    dock: 'bottom',
                    items: [                        
                        {
                            text: this.resetText,
                            handler: function() {
                                form.reset();
                            }
                        },
                        {xtype: 'spacer'},
                        {
                            text: this.addText,
                            ui: 'confirm',
                            scope: this,
                            handler: function() {
                            	var newTransaction = Ext.ModelMgr.create({}, 'TransactionAnnotation');
                            	var valid = false;
                            	form.updateRecord(newTransaction, true);
                            	newTransaction.commit();     
                            	
                            	if (newTransaction.data.sourceAccountID == 0)
                            		newTransaction.data.sourceAccountID = null;
                            	
                            	if (newTransaction.data.destinationAccountID == 0)
                            		newTransaction.data.destinationAccountID = null;
                            	
                            	if (newTransaction.data.categoryAccountID == 0)
                            		newTransaction.data.categoryAccountID = null;
                            	
                            	if (newTransaction.data.sourceAccountID != null && newTransaction.data.description != null && newTransaction.data.amount != null)
                            		valid = true;
                            	
                            	if (!valid) {
                            		Ext.Msg.alert(this.newExpenseAnnotationText, this.fillRequiredText, Ext.emptyFn);
                            	} else { 
                            		                       	
	                            	form.setLoading(true);
	                            	QFinance.Remoting.MobileAction.addTransactionAnnotation(newTransaction.data, function(result, event) {	                            		
	                            		var messsage = '';
	                            		var where = '';
	                            		var failure = false;
	                            		
	                            		form.setLoading(false);
	                            		
	                            		if (result) {
	                            			if (result.success) {
	                            				form.reset();		
	                            			} else {
	                            				failure = true;						
	                            				message = this.internalServerErrorText;	                            				
	                            			}            
	                            		} else {
	                            			failure = true;
	                            			message = this.internalServerErrorText;
	                            		}
	                            		
	                            		if (failure) {
	                            			Ext.Msg.alert(this.newExpenseAnnotationText, message, Ext.emptyFn);					
	                            			QFinance.service.DeveloperService.log('Direct call failure: ' + message + ' where\n' + where);	                            			
	                            		} else {
	                            			
	                            		}	                            			                            	
	                            	}, this);
                            	}
                            }
                        }
                    ]
                }
            ]
        };
        
        if (Ext.is.Phone) {
            formBase.fullscreen = true;
        } else {
            Ext.apply(formBase, {
                autoRender: true,
                floating: true,
                modal: true,
                centered: true,
                hideOnMaskTap: false,
                height: 385,
                width: 480
            });
        }
                
        QFinance.Remoting.MobileAction.getAccountsPlusNone(function(result, event) {
        	accountsStore.loadData( result.data );
        	this.sourceAccountCombo.setValue(null);
        	this.destinationAccountCombo.setValue(null);
        	QFinance.Remoting.MobileAction.getAccountsByTypePlusNone(1, function(result, event) {
        		privateAccountsStore.loadData( result.data );
                QFinance.Remoting.MobileAction.getCategoriesPlusNone(function(result, event) {
                	categoriesStore.loadData( result.data );
                	this.categoryCombo.setValue(null);
                	form.setLoading(false);
                }, this);
        	}, this); 
        }, this);
        
        form = new Ext.form.FormPanel(formBase);
        form.setLoading(true);
        form.show();
	}
});


Ext.namespace("QFinance.component");
/*
 * @depends component.js
 */
QFinance.component.AccountOverviewPanel = Ext.extend( Ext.Panel, {
    // Configuration
    accountID: null,
	
    // Localization
    balanceText: 'Balance',
    statisticsText: 'Statistics',	
	
    // Subcomponents
    formPanel: null,
	
    initComponent: function() {
        Ext.apply(this,{
            layout: 'fit',				
            items: [ this.formPanel = new Ext.form.FormPanel({					
                xtype: 'form',
                layout: 'hbox',								        
                items: [{
                    xtype: 'fieldset',
                    flex: 1,
                    title: this.balanceText,				        
                    margins: '0 5 0 0',
                    defaults: {
                        anchor: '100%'
                    },
                    items: [{
                        xtype: 'displayfield',
                        fieldLabel: 'Account balance',
                        name: 'accountBalance'							
                    },{
                        xtype: 'displayfield',
                        fieldLabel: 'Info 2',
                        name: 'test'
                    },{
                        xtype: 'displayfield',
                        fieldLabel: 'Info 3',
                        name: 'test'
                    },{
                        xtype: 'displayfield',
                        fieldLabel: 'Info 4',
                        name: 'test'
                    }]						
                },{
                    xtype: 'fieldset',
                    flex: 1,
                    title: this.statisticsText,
                    defaults: {
                        anchor: '100%'
                    },
                    items: [{
                        xtype: 'displayfield',
                        fieldLabel: 'Info 1',
                        name: 'test'
                    },{
                        xtype: 'displayfield',
                        fieldLabel: 'Info 2',
                        name: 'test'
                    },{
                        xtype: 'displayfield',
                        fieldLabel: 'Info 3',
                        name: 'test'
                    },{
                        xtype: 'displayfield',
                        fieldLabel: 'Info 4',
                        name: 'test'
                    }]						
                }],
                api: {
                    load: QFinance.Remoting.AccountOverviewPanelAction.getAccountOverview
                },
                paramOrder: [ 'accountID' ]
            })]
        });
        QFinance.component.AccountOverviewPanel.superclass.initComponent.call(this);
    },
	
    load: function( accountID ) {
        this.getEl().mask('Loading');
        this.accountID = accountID;
        this.formPanel.load({
            scope: this,
            params: {
                accountID: accountID
            },
            
            success: function(form, action) {
                /*
            	this.formPanel.items.get(0).items.get(0).removeClass('qfinance-red');
            	this.formPanel.items.get(0).items.get(0).removeClass('qfinance-blue');
            	
            	if (action.result.data.accountBalance >= 0)
            		this.formPanel.items.get(0).items.get(0).addClass('qfinance-blue');
            	else {
            		this.formPanel.items.get(0).items.get(0).addClass('qfinance-red');
            		this.formPanel.items.get(0).items.get(0).setValue(action.result.data.accountBalance *= -1);
            	}*/
            	
                this.getEl().unmask();
            }
        });
    }
});
Ext.reg('QFinance.component.AccountOverviewPanel', QFinance.component.AccountOverviewPanel);
Ext.namespace("QFinance.module");

QFinance.module.Module = function(config){
    Ext.apply(this, config);
    QFinance.module.Module.superclass.constructor.call(this);
    this.init();
};

Ext.extend(QFinance.module.Module, Ext.util.Observable, {
    init : Ext.emptyFn,
    setApp : function(app) {
    	this.app = app;
    }
});
/*
 * @depends module.js
 */
QFinance.module.MarksModule = Ext.extend(QFinance.module.Module, {
    // Configuration
    id: 'QFinance.module.MarksModule',
	
    // Localization
    marksText: 'Marks',
    closeText: 'Close',	
    
    init : function(){
        this.launcher = {
            text: this.marksText,
            iconCls: 'fugue-bookmarks',
            handler: this.createWindow,
            scope: this
        };
    },
    
    createWindow : function(){		
        var desktop = this.app.getDesktop();
        var win = desktop.getWindow('QFinance.module.MarksModule.createWindow.win');
        var marksEditPanel;
        if(!win){	    	
            win = desktop.createWindow({
                id: 'QFinance.module.MarksModule.createWindow.win',
                title: this.marksText,
                width: 480,
                height: 300,
                iconCls: 'fugue-bookmarks',
                animCollapse: false,
                layout: 'fit',	            
                items: [ marksEditPanel = new QFinance.component.MarksEditPanel() ],
                listeners: {
                    show: function() {
                        marksEditPanel.loadRecords();
                    }
                },
                bbar: [new Ext.Button({
                    text: this.closeText,
                    iconCls: 'fugue-door-open-out',	
                    handler: function() {
                        win.close();				
                    }
                })],
                stateful: true
            }, QFinance.ui.Window);
        }
        win.show();
    }
});
/*
 * @depends module.js
 */
QFinance.module.ExpensesAndIncomesByCategoryModule = Ext.extend(QFinance.module.Module, {
    // Configuration
    id: 'QFinance.module.ExpensesAndIncomesByCategoryModule',	
	
    // Localization
    expensesAndIncomesByCategoryText: 'Expenses and incomes by category',
    closeText: 'Close',
	    
    init: function() {
        this.launcher = {
            text: this.expensesAndIncomesByCategoryText,
            iconCls: 'fugue-report',
            handler: this.createWindow,
            scope: this
        };
    },
    
    createWindow: function() {		
        var desktop = this.app.getDesktop();
        var win = desktop.getWindow('QFinance.module.ExpensesAndIncomesByCategoryModule.createWindow.win');
        var expensesAndIcomesByCategoryPanel;
        if (!win){
            win = desktop.createWindow({
                id: 'QFinance.module.ExpensesAndIncomesByCategoryModule.createWindow.win',
                title: this.expensesAndIncomesByCategoryText,
                width: 700,
                height: 500,
                iconCls: 'fugue-report',
                layout: 'fit',
                items: [  
                expensesAndIcomesByCategoryPanel = new QFinance.component.ExpensesAndIncomesByCategoryPanel()
                ],
                listeners: {
                    scope: this,
                    show: function() {
                        expensesAndIcomesByCategoryPanel.autoLoadData();
                    }
                },
                bbar: [new Ext.Button({
                    text: this.closeText,
                    iconCls: 'fugue-door-open-out',
                    handler: function() {
                        win.close();
                    }
                })],
                stateful: true
            }, QFinance.ui.Window);
        }
        win.show();
    }
});
/*
 * @depends module.js
 */
QFinance.module.DeveloperConsoleModule = Ext.extend(QFinance.module.Module, {
    // Configuration
    id: 'QFinance.module.DeveloperConsoleModule',	
	
    // Localization
    developerConsoleText: 'Developer Console',
    startText: 'Start',
    stopText: 'Stop',
    updateText: 'Update',
    clearText: 'Clear',
    closeText: 'Close',
    
    init : function(){
        this.launcher = {
            text: this.developerConsoleText,
            iconCls: 'fugue-terminal',
            handler: this.createWindow,
            scope: this
        };
    },
    
    createWindow : function(){		
        var desktop = this.app.getDesktop();
        var win = desktop.getWindow('QFinance.module.DeveloperConsoleModule.createWindow.win');
        var logPanel;
        var running;
        
        if(!win){	    		    	
            var monitorButton = new Ext.Button({
                text: (QFinance.service.DeveloperService.running ? this.stopText : this.startText),
                iconCls: (QFinance.service.DeveloperService.running ? 'fugue-control-pause' : 'fugue-control'),
                scope: this,
                handler: function() {
                    if (QFinance.service.DeveloperService.running) {
                        monitorButton.setText(this.startText);
                        monitorButton.setIconClass('fugue-control');
                        QFinance.service.DeveloperService.stopMonitor();
                        running = false;
                    } else {
                        monitorButton.setText(this.stopText);
                        monitorButton.setIconClass('fugue-control-pause');
                        QFinance.service.DeveloperService.startMonitor();
                        running = true;
                    }
                }
            });
	    	
            win = desktop.createWindow({
                id: 'QFinance.module.DeveloperConsoleModule.createWindow.win',
                title: this.developerConsoleText,
                width: 480,
                height: 200,
                iconCls: 'fugue-terminal',
                animCollapse: false,
                layout: 'fit',	            
                items: [ 
                logPanel = new Ext.Panel({
                    xtype: 'panel',
                    autoScroll: true,
                    region: 'center',
                    border: false,
                    style: 'border-width:0 1px 0 0',
			
                    log : function(){
                        var markup = [  '<div style="padding:5px !important;border-bottom:1px solid #ccc;">',
                        Ext.util.Format.htmlEncode(Array.prototype.join.call(arguments, ', ')).replace(/\n/g, '<br/>').replace(/\s/g, '&#160;'),
                        '</div>'].join(''),
                        bd = this.body.dom;
			
                        this.body.insertHtml('beforeend', markup);
                        bd.scrollTop = bd.scrollHeight;				            
                    },
			
                    clear : function(){
                        this.body.update('');
                        this.body.dom.scrollTop = 0;
                    },
				        
                    bbar: [
                    monitorButton,
                    '->',
                    {
                        text: this.updateText,
                        iconCls: 'fugue-arrow-circle',
                        handler: function() {
                            QFinance.service.DeveloperService.getMessages();
                        }
                    },
                    {
                        text: this.clearText,
                        iconCls: 'fugue-broom',
                        handler: function() {
                            logPanel.clear();
                        }
                    },{
                        text: this.closeText,
                        iconCls: 'fugue-door-open-out',
                        handler: function() {
                            win.close();
                        }
                    }]
                })
                ],
                stateful: true
            });
            QFinance.service.DeveloperService.on('print', logPanel.log, logPanel);
        }
        win.show();	    
    }
});
/*
 * @depends module.js
 */
QFinance.module.AnnotatedTransactionsModule = Ext.extend(QFinance.module.Module, {
    // Configuration
    id: 'QFinance.module.AnnotatedTransactionsModule',	
	
    // Localization
    transactionsText: 'Annotated transactions',
    selectAccountText: 'Select an account:',
    closeText: 'Close',
    
    // Components
    transactionsEditPanel: null,
    accountStore: null,
    
    init : function(){
        this.launcher = {
            text: this.transactionsText,
            iconCls: 'fugue-sticky-notes',
            handler: this.createWindow,
            scope: this
        };        
    },
    createWindow : function(){		
        var desktop = this.app.getDesktop();
        var win = desktop.getWindow('QFinance.module.AnnotatedTransactionsModule.createWindow.win');
        if (!win){
            this.accountStore = new Ext.data.DirectStore({    		
                directFn: QFinance.Remoting.AccountAction.getByAccountType,
                paramsAsHash: false,
                autoLoad: true,
                paramOrder: [ 'type' ],
                baseParams: {
                    type: '1'
                },
                idProperty: 'id',
                root: 'data',
                successProperty: 'success',
                fields: [
                {
                    name: 'id',
                    type: 'int'
                },
                {
                    name: 'accountName'	    		    
                },
                {
                    name: 'accountType'
                }
                ],
                listeners: {
                    scope: this,
                    beforeload: function(store, options) {
                        store.id = win.getProcessStatusManager().start([[win.topToolbar]]);
                    },				
                    load: function(store, records, options) {
                        win.getProcessStatusManager().success(store.id);
                    },
                    exception: function(dataProxy, type, action, options, response, arg ) {
                        var message = '';
                        var where = '';
                        if (response.result) {
                            message = response.result.message;
                            if (response.result.type == 'exception')
                                where = response.result.where;
                        } else {
                            message = response.message;
                        }
                        win.getProcessStatusManager().error(this.accountStore.id, message);
                        QFinance.service.DeveloperService.log('Store failure: ' + message + ' where\n' + where);
                    }
                }   		
            });
	    	
            win = desktop.createWindow({
                id: 'QFinance.module.AnnotatedTransactionsModule.createWindow.win',
                title: this.transactionsText,
                width: 740,
                height: 480,
                iconCls: 'fugue-sticky-notes',
                animCollapse: false,
                layout: 'fit',
                items: [this.transactionsEditPanel = new QFinance.component.TransactionsEditPanel({                    
                    disabled: true,
                    showAccountOverview: false,
                    showAccountBalance: false,
                    onlyAnnotations: true,
                    canAddTransaction: true,
                    canEditTransaction: true,
                    canRemoveTransaction: true,
                    onlyAnnotation: true,
                    canViewSubtransactions: false,
                    recordDragDrop: true,
                    forceCategorySelection: false
                })],
                tbar: [
                this.selectAccountText,
                {
                    xtype: 'combo',
                    store: this.accountStore,
                    typeAhead: true,
                    triggerAction: 'all',
                    selectOnFocus: true,
                    valueField: 'id',
                    displayField: 'accountName',
                    mode: 'local',
                    listeners: {
                        scope: this,
                        select: function(comboBox, record, index) {	              			
                            this.transactionsEditPanel.contextAccountID = record.get('id');
                            this.transactionsEditPanel.load();
                            this.transactionsEditPanel.enable();
                        }
                    }
                }],
                bbar: [new Ext.Button({
                    text: this.closeText,
                    iconCls: 'fugue-door-open-out',	
                    scope: this,
                    handler: function() {					
                        win.close();					
                    }
                })],
                stateful: true
            }, QFinance.ui.Window);
        }
        win.show();
    }
});
/*
 * @depends module.js
 */
QFinance.module.AccountsModule = Ext.extend(QFinance.module.Module, {
    // Configuration
    id: 'QFinance.module.AccountsModule',
	
    // Localization
    accountsText: 'Accounts',
    closeText: 'Close',	
    
    init : function(){
        this.launcher = {
            text: this.accountsText,
            iconCls: 'fugue-wallet',
            handler: this.createWindow,
            scope: this
        };
    },
    
    createWindow : function(){		
        var desktop = this.app.getDesktop();
        var win = desktop.getWindow('QFinance.module.AccountsModule.createWindow.win');
        var accountsEditPanel;
        if(!win){	    	
            win = desktop.createWindow({
                id: 'QFinance.module.AccountsModule.createWindow.win',
                title: this.accountsText,
                width: 480,
                height: 300,
                iconCls: 'fugue-wallet',
                animCollapse: false,
                layout: 'fit',	            
                items: [ accountsEditPanel = new QFinance.component.AccountsEditPanel() ],
                listeners: {
                    show: function() {
                        accountsEditPanel.autoLoadData();
                    }
                },
                bbar: [new Ext.Button({
                    text: this.closeText,
                    iconCls: 'fugue-door-open-out',	
                    handler: function() {
                        win.close();				
                    }
                })],
                stateful: true
            }, QFinance.ui.Window);
        }
        win.show();
    }
});
/*
 * @depends module.js
 */
QFinance.module.OverviewModule = Ext.extend(QFinance.module.Module, {
    // Configuration
    id: 'QFinance.module.OverviewModule',
	
    // Localization
    overviewText: 'Overview',
    closeText: 'Close',

    init : function(){
        this.launcher = {
            text: this.overviewText,
            iconCls: 'globe-green',
            handler: this.createWindow,
            scope: this
        };
    },
    
    createWindow : function(){
        var overviewPanel = null;
        var desktop = this.app.getDesktop();
        var win = desktop.getWindow('QFinance.module.OverviewModule.createWindow.win');
        if(!win){	
            win = desktop.createWindow({
                id: 'QFinance.module.OverviewModule.createWindow.win',
                title: this.overviewText,
                width: 400,
                height: 450,
                iconCls: 'globe-green',
                animCollapse: false,
                layout: 'fit',	            
                items: [ overviewPanel = new QFinance.component.OverviewPanel() ],
                listeners: {
                    show: function() {
                        overviewPanel.loadPortlets();
                    }
                },
                bbar: [new Ext.Button({
                    text: this.closeText,
                    iconCls: 'fugue-door-open-out',	
                    handler: function() {
                        win.close();				
                    }
                })],
                stateful: true
            }, QFinance.ui.Window);
        }
        win.show();
    }
});
/*
 * @depends module.js
 */
QFinance.module.ReportsModule = Ext.extend(QFinance.module.Module, {
    // Configuration
    id: 'QFinance.module.ReportsModule',
	
    // Localization
    reportsText: 'Reports',
	
    // Others
    modules: null,
	
    init : function(){
        this.launcher = {
            text: this.reportsText,
            iconCls: 'fugue-reports',
            handler: function() {
                return false;
            },
            menu: {
                items: []
            }
        };
        this.modules = this.getModules();
        if (this.modules)
            this.initModules(this.modules);  
    },
    
    getModules : function() {
        return [
        new QFinance.module.ExpensesAndIncomesByCategoryModule()
        ];
    },
    
    initModules : function(ms) {
        for(var i = 0, len = ms.length; i < len; i++){
            var m = ms[i];
            this.launcher.menu.items.push(m.launcher);
            m.app = this.app;
        }
    },
    
    setApp : function(app) {   
        var ms = this.modules;
        for(var i = 0, len = ms.length; i < len; i++){
            var m = ms[i];
            m.setApp(app);            
        }    	
        QFinance.module.ReportsModule.superclass.setApp.call(this,app);
    }
});
/*
 * @depends module.js
 */
QFinance.module.TestModule = Ext.extend(QFinance.module.Module, {
    id:'test-win',
    init : function(){
        this.launcher = {
            text: 'Test',
            iconCls: 'fugue-burn',
            handler: this.createWindow,
            scope: this
        };
    },
	createWindow : function(){		
	    var desktop = this.app.getDesktop();
	    var win = desktop.getWindow('transaction-win');
	    if(!win){	    	
	    	
	        win = desktop.createWindow({
	            id: 'transaction-win',
	            title: 'Transactions',
	            width: 740,
	            height: 480,
	            iconCls: 'fugue-burn',
	            animCollapse: false,
	            layout: 'fit',
	            items: [new QFinance.component.TransactionsEditPanel({
	            	contextAccountID: 1,
					autoLoadTransactions: true
	            })]
	        });
	    }
	    win.show();
	}
});
/*
 * @depends module.js
 */
QFinance.module.TransactionsImportModule = Ext.extend(QFinance.module.Module, {
    // Configuration
    id: 'QFinance.module.TransactionsImportModule',	
	
    // Localization
    closeText: 'Close',
    importText: 'Import',
	
    // Others
    transactionsImportPanel: null,
        
    init: function() {
        this.launcher = {
            text: this.importText,
            iconCls: 'fugue-money--arrow',
            handler: this.createWindow,
            scope: this
        };
    },
    createWindow: function() {		
        var desktop = this.app.getDesktop();
        var win = desktop.getWindow('QFinance.module.TransactionsImportModule.createWindow.win');
        if (!win){
            win = desktop.createWindow({
                id: 'QFinance.module.TransactionsImportModule.createWindow.win',
                title: this.importText,
                width: 700,
                height: 500,
                iconCls: 'fugue-money--arrow',
                layout: 'fit',
                items: [ this.transactionsImportPanel = new QFinance.component.TransactionsImportPanel({
                    listeners: {
                        importData: function() {
                            win.close();
                        }
                    }
                })],
                bbar: [new Ext.Button({
                    text: this.closeText,
                    iconCls: 'fugue-door-open-out',	
                    scope: this,
                    handler: function() {
                        this.transactionsImportPanel.checkTemporaryTransactionsGhosts();
                        win.close();					
                    }
                })],
                stateful: true
            }, QFinance.ui.Window);
        }
        win.show();
    }
});
/*
 * @depends module.js
 */
QFinance.module.UsersModule = Ext.extend(QFinance.module.Module, {
    // Configuration
    id: 'QFinance.module.UsersModule',
	
    // Localization
    usersText: 'Users',
    closeText: 'Close',
	    
    init : function(){
        this.launcher = {
            text: this.usersText,
            iconCls: 'fugue-users',
            handler: this.createWindow,
            scope: this
        };
    },
    
    createWindow : function(){		
        var desktop = this.app.getDesktop();
        var win = desktop.getWindow('QFinance.module.UsersModule.createWindow.win');
        if(!win){	
            win = desktop.createWindow({
                id: 'QFinance.module.UsersModule.createWindow.win',
                title: this.usersText,
                width: 280,
                height: 300,
                iconCls: 'fugue-users',
                animCollapse: false,
                layout: 'fit',	            
                items: [ new QFinance.component.UsersEditPanel() ],
                bbar: [new Ext.Button({
                    text: this.closeText,
                    iconCls: 'fugue-door-open-out',	
                    handler: function() {
                        win.close();				
                    }
                })],
                stateful: true
            }, QFinance.ui.Window);
        }
        win.show();
    }
});
Ext.ns('QFinance.portlet');
/*
 * @depends portlet.js
 */
QFinance.portlet.PortletFactory = Ext.extend( Object, {
	getPortletInstanceByClass: function( className ) {
		var portlet = eval('new QFinance.portlet.' + className + '()');
		
		if (portlet)
			portlet.className = className;
		
		return portlet;		
	}
});

QFinance.portlet.PortletFactory = new QFinance.portlet.PortletFactory();
Ext.namespace("QFinance");

QFinance.dateFormat = 'Y-m-d';
QFinance.decimalSeparator = '.';
QFinance.moneySymbol = 'U$';
QFinance.numberFormat = '0,000.00';
QFinance.loadingText = 'Loading...';
/**
 * @depends qfinance.js
 */
QFinance.LoginWindow = Ext.extend( Ext.Window, {
    isLogged : false,
    
    // Localization
    failureText: 'Failure',
    invalidText: 'Invalid username and/or password.',
    usernameText: 'Username',
    passwordText: 'Password',
    loginText: 'Enter',
    waitText: 'Wait',
    waitMsgText: 'Authenticating...',
    title: 'Login',
    
    submitHandler : function(b, e){
        var loginForm = Ext.getCmp('loginForm');
        loginForm.getForm().submit({
            waitTitle: this.waitText,
            waitMsg: this.waitMsgText,
            success: this.validateLogin,
            failure: this.showFailureMessage,
            scope: this
        }, this);
    },
	
    constructor: function(config) {
        Ext.apply(this, config);
        Ext.apply(this,{			
            width: 250,
            layout: 'fit',
            autoHeight: true,
            closable: false,
            closeAction: 'close',
            items: [ {
                xtype: 'form',
                id: 'loginForm',
                autoHeight: true,
                labelWidth: 60,	            
                frame: true,
                defaultType: 'textfield',
                monitorValid: true,
                items: [
                {
                    id: 'QFinance.LoginWindow.LoginForm.Username',
                    fieldLabel: this.usernameText,
                    allowBlank: false,
                    name: 'username'
                },
                {
                    fieldLabel: this.passwordText,
                    inputType: 'password',
                    allowBlank: false,
                    name: 'password'	                    
                }
                ],
                buttons: [{
                    text: this.loginText,
                    formBind: true,
                    scope: this,	            	
                    handler: this.submitHandler  	
                }],
                api: {
                    submit: QFinance.Remoting.LoginAction.login
                },
                keys: [
                {
                    key: [Ext.EventObject.ENTER], 
                    handler: this.submitHandler, 
                    scope: this
                }
                ]
            }
            ]		
        });
		
        this.addEvents({
            'logged' : true
        });	
	    
        QFinance.LoginWindow.superclass.constructor.call(this);
    },
	
    validateLogin: function(form, action) {
        if (action.result.logged) {
            this.isLogged = true;
            this.fireEvent('logged', this);
            this.destroy();
        } else {
            Ext.Msg.alert(this.failureText, this.invalidText);
        }
    },
	
    showFailureMessage: function(form, action) {
        var message = '';
        var where = '';
        switch (action.failureType) {			
            case Ext.form.Action.CLIENT_INVALID:
                message = 'Form fields may not be submitted with invalid values';			    
                break;
            case Ext.form.Action.CONNECT_FAILURE:
                message = 'Ajax communication failed';
                break;
            case Ext.form.Action.SERVER_INVALID:
                message = action.result.message;
                if (action.result.type == 'exception')
                    where = action.result.where;
                break;
        }
        QFinance.service.DeveloperService.log('Submit failure: ' + message + ' where\n' + where);
    },
	
    onLogged : function(fn, scope){
        if (this.isLogged) {
            this.on( 'logged', fn, scope );
        } else {
            fn.call(scope, this);
        }
    },
	
    onShow: function() {
        Ext.Window.superclass.onShow.call(this);
        Ext.getCmp('QFinance.LoginWindow.LoginForm.Username').focus(true,10);
    }
});
Ext.namespace('QFinance.service');
/*
 * @depends service.js
 */
QFinance.service.DeveloperService = Ext.extend(Ext.util.Observable, {
    task: null,
			
    running: false,
	
    constructor: function() {
        this.task = {
            run: this.getMessages,
            interval: 1000,
            scope: this
        };
		
        this.addEvents(['print']);
    },
	
    log: function( message ) {
        if (this.logMessages)
            this.print( 'Javascript: ' + message);		
    },
	
    print: function( message ) {
        if (window.console)
            window.console.info( message );
        this.fireEvent('print', message);
    },
	
    startMonitor: function() {
        this.running = true;
        Ext.TaskMgr.start(this.task);
    },
	
    stopMonitor: function() {
        this.running = false;
        Ext.TaskMgr.stop(this.task);
    },
	
    getMessages: function() {
        QFinance.Remoting.DeveloperServiceAction.getMessages(function(messages, event) {
            Ext.each(messages, function( message ) {
                this.print( 'PHP: ' + message );
            }, this);                		
        }, this);	
    },
	
    load: function(callback, scope) {
        QFinance.Remoting.DeveloperServiceAction.getConfiguration(function(result, event) {
            var message = '';
            var where = '';
            var failure = false;
			
            if (result) {
                if (result.success) {
                    Ext.apply(this, result.configuration);
                    if (callback) callback.call(scope||this);		
                } else {
                    failure = true;						
                    message = result.message;
                    if (result.type == 'exception')
                        where = result.where;
                }            
            } else {
                failure = true;
                message = event.message;
            }
			
            if (failure) {			
                QFinance.service.DeveloperService.log('Direct call failure: ' + message + ' where\n' + where);
            }                		
        }, this);			
    }
});
QFinance.service.DeveloperService = new QFinance.service.DeveloperService();
Ext.namespace('QFinance.ui');
/**
 * @depends ui.js
 */
QFinance.ui.StatusBar = Ext.extend( Ext.ux.StatusBar, {
    showBusy: function(message) {
        this.setStatus({
            text: message,
            iconCls: 'x-status-busy'
        });	
    },

    clear: function() {
        this.clearStatus({
            useDefaults: false
        });
    }
});
Ext.reg('qstatusbar', QFinance.ui.StatusBar);
/*
 * @depends ui.js
 */
QFinance.ui.SelectWindow = Ext.extend( Ext.Window, {
    // Localization
    title: 'Select an option',
    OKText: 'OK',
    cancelText: 'Cancel',
	
    constructor: function(cfg) {
        Ext.apply(this, cfg);
		
        QFinance.ui.SelectWindow.superclass.constructor.call(this);
    },
	
    initComponent: function() {
        Ext.apply(this, {			
            //resizable: false,
            constrain: true,
            buttonAlign: 'center',
            autoHeight: true,            
            width: 300,
            closable: true,
            plain: true,
            shim: true,
            border: false,
            items: [{
                layout: 'anchor',
                style: 'padding: 10px',
                defaults: {
                    anchor: '100%'
                },
                items: [this.selectComboBox = new Ext.form.ComboBox({				
                    xtype: 'combo',		    		
                    fieldLabel: '',		    		
                    typeAhead: true,		    		
                    triggerAction: 'all',
                    emptyText: this.title,
                    selectOnFocus: true,
                    forceSelection: true,
                    store: this.options,
                    hiddenName: 'bankID',
                    name: 'bank'
                })]
            }],			
            fbar: {
                autoWidth: true,
                autoHeight: true,
                items: [{
                    text: this.OKText,
                    scope: this,
                    autoWidth: true,
                    handler: function() {
                        if (this.selectComboBox.selectedIndex >= 0) {
                            this.close();
                            Ext.callback(this.handler, this.scope||this, [ this.selectComboBox.getValue() ], 1);
                        }
                    }
                },{
                    text: this.cancelText,
                    scope: this,
                    autoWidth: true,
                    handler: function() {
                        this.close();
                    }
                }]
            }
        });
        QFinance.ui.SelectWindow.superclass.initComponent.call(this);
    }
});
/**
 * @depends ui.js
 */
QFinance.ui.ProcessStatusManager = Ext.extend( Ext.util.Observable, {
    constructor: function(cfg) {
        this.processes = [];
        
        Ext.apply(cfg);
        this.addEvents('statusupdate');
    },
    
    start: function(components) {
        var id = Ext.id();
        this.processes.push({
            id: id,
            status: QFinance.ui.ProcessStatusManager.STARTED,
            components: components,
            message: ''
        });        
        this.doStatusUpdate();
        return id;
    },
    
    success: function(id, message) {
        this.end(id, QFinance.ui.ProcessStatusManager.ENDED, message);
    },
    
    error: function(id, message) {
        this.end(id, QFinance.ui.ProcessStatusManager.ERROR, message);
    },
    
    end: function(id, status, message) {
        for (var i = 0; i < this.processes.length; i++) {
            if (this.processes[i].id == id) {                
                this.processes[i].status = status;
                this.processes[i].message = message;              
            }
        }                
        this.doStatusUpdate();
    },
        
    doStatusUpdate: function() {                
        this.fireEvent('statusupdate', this, this.processes);
    }
});

QFinance.ui.ProcessStatusManager.STARTED = 0;
QFinance.ui.ProcessStatusManager.ENDED = 1;
QFinance.ui.ProcessStatusManager.ERROR = 2;
/*
 * @depends ui.js
 */
QFinance.ui.Portlet = Ext.extend( Ext.ux.Portlet, {
    configurationWindow: null,
    iconCls: 'puzzle',
    internalID: null,
    refreshText: 'Refresh',
    configureText: 'Configure',
    closeText: 'Close',
	
    initComponent: function() {
        this.initTools();
        QFinance.ui.Portlet.superclass.initComponent.call(this);
    },
	
    initTools: function() {
        this.tools = [{
            id:'refresh',
            qtip: this.refreshText,
            scope: this,
            handler: function(e, target, panel){
                this.loadData(panel.ownerCt.ownerCt);
            }
        },{
            id:'gear',
            qtip: this.configureText,
            scope: this,
            handler: function(e, target, panel){
                this.configure(panel.ownerCt.ownerCt);
            }
        },{
            id:'close',
            qtip: this.closeText,
            scope: this,
            handler: function(e, target, panel){
                if (this.internalID)
                    panel.ownerCt.ownerCt.markToRemove(this);
                panel.ownerCt.remove(panel, true);
            }
        }];
    },
	
    configure: function(portal, callback, scope) {
        if (this.configurationWindow) {
            var cfg = {
                configuration: this.configuration, 
                ownerWindow: portal.ownerCt,
                listeners: {
                    scope: this,
                    save: function( configuration ) {
                        this.configuration = configuration;
                        if (callback)
                            callback.call(scope || this);
                        this.loadData();
                    }
                }
            };
            var configurationWindowInstance = eval('new QFinance.portlet.' + this.configurationWindow + '(cfg)');
            if (configurationWindowInstance) {				
                configurationWindowInstance.show();
            }
        } else {
            if (callback)
                callback.call(scope || this);
            this.loadData();
        }
    }
});
/**
 * @depends Portlet.js,portlet.js
 */
QFinance.portlet.AccountsBalanceHistoryPortlet = Ext.extend( QFinance.ui.Portlet, {
    configurationWindow: 'AccountsBalanceHistoryConfigurationWindow',	
    configuration: {
        accountID: null,
        range: 2,
        startDate: null,
        endDate: null,
        type: 1
    },
	
    // Localization
    title: 'Accounts balance history',
    accountText: 'Account',
    rangeText: 'Range',
    typeText: 'Type',
    amountText: 'Amount',
		
    constructor: function(cfg) {
        Ext.apply(this, cfg);
        QFinance.portlet.AccountsBalanceHistoryPortlet.superclass.constructor.call(this);
    },
	
    initComponent: function() {		
        this.initStore();		
        Ext.apply(this, {
            layout: 'vbox',
            layoutConfig: {
                align : 'stretch',
                pack  : 'start'
            },
            height: 300,
            items: [{
                xtype: 'form',
                autoHeight: true,
                labelWidth: 60,
                style: 'padding: 10px 10px 0px 10px',
                defaults: {
                    anchor: '100%'
                },
                items: [ this.accoutNameField = new Ext.form.DisplayField({
                    name: 'accountName',
                    xtype: 'displayfield',
                    fieldLabel: this.accountText
                }),
                this.rangeNameField = new Ext.form.DisplayField({
                    name: 'rangeName',
                    xtype: 'displayfield',
                    fieldLabel: this.rangeText
                }),
                this.typeNameField = new Ext.form.DisplayField({
                    name: 'typeName',
                    xtype: 'displayfield',
                    fieldLabel: this.typeText
                })]
            },{
                xtype: 'highchart',
                flex: 1,
                store: this.store,
                series: [{
                    type: 'area',
                    dataIndex: 'amount',
                    xField: 'date'
                }],
                chartConfig: {
                    chart: {						
                        zoomType: 'x'						
                    },
                    title: {
                        text: null
                    },
                    xAxis: [{
                        title: {
                            text: this.rangeText
                        },
                        type: 'datetime',
                        maxZoom: 1000 * 3600 * 24 * 7 // 1 semana
                    }],
                    yAxis: [{
                        title: {
                            text: this.amountText
                        },
                        labels: {
                            formatter: function() {
                                return QFinance.moneySymbol + ' ' + Ext.util.Format.number(this.value,QFinance.numberFormat);
                            }
                        }						
                    }],
                    plotOptions: {
                        area: {
                            marker: {
                                enabled: false,
                                symbol: 'circle',
                                radius: 2,
                                states: {
                                    hover: {
                                        enabled: true
                                    }
                                }
                            }
                        }
                    },
                    credits: {
                        enabled: false
                    },
                    legend: {
                        enabled: false
                    },
                    tooltip: {
                        formatter: function() {
                            var tooltip = '';
                            tooltip += '<span style="font-size: 10px">' + Highcharts.dateFormat('%A, %b %e, %Y', this.x) + '</span><br/>';
                            if (this.y >= 0 )
                                tooltip += '<span style="color:green;">' + QFinance.moneySymbol + ' ' + Ext.util.Format.number(this.y,QFinance.numberFormat) + '</span>';
                            else
                                tooltip += '<span style="color:red;">' + QFinance.moneySymbol + ' ' + Ext.util.Format.number(this.y,QFinance.numberFormat) + '</span>';
                            return tooltip;
                        }
                    }
                }				
            }]
        });	
		
        QFinance.portlet.AccountsBalanceHistoryPortlet.superclass.initComponent.call(this);
    },
	
    initStore: function() {
        this.store = new Ext.data.DirectStore({
            autoLoad: false,
            idProperty: 'id',
            root: 'data',
            successProperty: 'success',
            paramsAsHash: false,
            paramOrder: [ 'accountID', 'range', 'startDate', 'endDate', 'type' ],
            baseParams: {
                accountID: this.configuration.accountID, 
                range: this.configuration.range, 
                startDate: this.configuration.startDate, 
                endDate: this.configuration.endDate, 
                type: this.configuration.type
            },
            api: {
                read: QFinance.Remoting.AccountsBalanceHistoryPortletAction.read
            },
            fields: [{
                name: 'date',
                type: 'int'				
            },				
            'amount'
            ],
            listeners: {
                scope: this,
                beforeload: function(store, options) {
                    this.body.mask(QFinance.loadingText, 'x-mask-loading');		
                },				
                load: function(store, records, options) {					
                    this.body.unmask();
                },
                exception: function(dataProxy, type, action, options, response, arg ) {
                    var message = '';
                    var where = '';
                    if (response.result) {
                        message = response.result.message;
                        if (response.result.type == 'exception')
                            where = response.result.where;
                    } else {
                        message = response.message;
                    }
                    this.body.mask(message);					
                    QFinance.service.DeveloperService.log('Store failure: ' + message + ' where\n' + where);
                }
            }				
        });
    },
	
    loadData: function() {
        this.accoutNameField.setValue(this.configuration.accountName);
        if (this.configuration.range == 6)
            this.rangeNameField.setValue(this.configuration.rangeName + ' - ' + this.configuration.startDate + ' to ' + this.configuration.endDate);
        else
            this.rangeNameField.setValue(this.configuration.rangeName);
        this.typeNameField.setValue(this.configuration.typeName);
        this.store.setBaseParam('accountID', this.configuration.accountID);
        this.store.setBaseParam('range', this.configuration.range);
        this.store.setBaseParam('startDate', this.configuration.startDate);
        this.store.setBaseParam('endDate', this.configuration.endDate);
        this.store.setBaseParam('type', this.configuration.type);
        this.store.load();
    }
});
/*
 * @depends Portlet.js,portlet.js
 */
QFinance.portlet.AccountsBalancePortlet = Ext.extend( QFinance.ui.Portlet, {
    store: null,
    accountBalanceRecord: null,
	
    // Localization
    title: 'Accounts balance',	
    accountText: 'Account',
    amountText: 'Amount',
	
    constructor: function(cfg) {
        Ext.apply(this, cfg);				
        QFinance.portlet.AccountsBalancePortlet.superclass.constructor.call(this);
    },
	
    initComponent: function() {
        this.createAccountBalanceRecord();
        this.initStore();
        this.initGrid();
        Ext.apply(this, {
            items: [ this.grid ]
        });
        QFinance.portlet.AccountsBalancePortlet.superclass.initComponent.call(this);
    },

    initStore: function() {
        this.store = new Ext.data.DirectStore({
            autoSave: false,
            autoLoad: false,		    
            idProperty: 'id',
            root: 'data',
            successProperty: 'success',  		
            api: {
                read: QFinance.Remoting.AccountsBalancePortletAction.read
            },
            fields: this.accountBalanceRecord,
            listeners: {
                scope: this,
                beforeload: function(store, options) {
                    this.body.mask(QFinance.loadingText, 'x-mask-loading');		
                },				
                load: function(store, records, options) {
                    this.body.unmask();
                },				
                exception: function(dataProxy, type, action, options, response, arg ) {
                    var message = '';
                    var where = '';
                    if (response.result) {
                        message = response.result.message;
                        if (response.result.type == 'exception')
                            where = response.result.where;
                    } else {
                        message = response.message;
                    }
                    this.body.unmask();
                    this.body.mask(message);					
                    QFinance.service.DeveloperService.log('Store failure: ' + message + ' where\n' + where);					
                }
            }			
        });
    },

	
    initGrid: function() {
        this.grid = new Ext.grid.GridPanel({				
            store: this.store,				
            autoHeight: true,
            columns: [
            {
                id       :'accountName',
                header   : this.accountText, 
                sortable : true, 
                dataIndex: 'accountName'
            },{
                id       :'amount',
                header   : this.amountText, 
                sortable : true, 
                dataIndex: 'amount',
                scope: this,
                renderer: function(value, metaData, record, rowIndex, colIndex, store) {
                    if (value >= 0) {
                        return '<span style="color:green;">' + QFinance.moneySymbol + ' ' + Ext.util.Format.number(value,QFinance.numberFormat) + '</span>';
                    } else {
                        return '<span style="color:red;">' + QFinance.moneySymbol + ' ' + Ext.util.Format.number(value,QFinance.numberFormat) + '</span>';
                    }	
                },	            
                summaryType: 'sum',
                summaryRenderer: function(value, params, data) {
                    if (value >= 0) {
                        return '<span style="color:green;">' + QFinance.moneySymbol + ' ' + Ext.util.Format.number(value,QFinance.numberFormat) + '</span>';
                    } else {
                        return '<span style="color:red;">' + QFinance.moneySymbol + ' ' + Ext.util.Format.number(value,QFinance.numberFormat) + '</span>';
                    }	            	
                }
            }],
            stripeRows: true,
            autoExpandColumn: 'accountName',
            sm: new Ext.grid.RowSelectionModel(),
            plugins: [new Ext.ux.grid.GridSummary()]
        });
    },
	
    createAccountBalanceRecord: function() {
        this.accountBalanceRecord = Ext.data.Record.create([{
            name: 'accountName'
        },{
            name: 'amount',	
            type: 'float'
        }]);
    },
	
    loadData: function() {		
        this.store.load();
    },	
	
    onLayout: function() {
        this.grid.getView().refresh();
        QFinance.portlet.AccountsBalancePortlet.superclass.onLayout.call(this);
    },
	
    onRender: function(ct, position) {
        QFinance.portlet.AccountsBalancePortlet.superclass.onRender.call(this, ct, position);		
    }
});
/*
 * @depends Portlet.js,portlet.js
 */
QFinance.portlet.TopAmountPortlet = Ext.extend( QFinance.ui.Portlet, {
    topAmountRecord: null,	
    configuration: {
        topType: null
    },
    configurationWindow: 'TopAmountPortletConfigurationWindow',
	
    // Localization
    titleText: 'Top',
    amountText: 'Amount',
    nameText: 'Name',
    categoryText: 'category',
    accountText: 'account',
    transactionText: 'transaction',
    markText: 'mark',
	
    constructor: function(cfg) {
        Ext.apply(this, cfg);		
        QFinance.portlet.TopAmountPortlet.superclass.constructor.call(this);
    },
	
    initComponent: function() {				
        this.createTopAmountRecord();
        this.initStore();
        this.initGrid();
        Ext.apply(this, {
            items: [ this.grid ]
        });
        QFinance.portlet.TopAmountPortlet.superclass.initComponent.call(this);
    },
	
    initStore: function() {
        this.store = new Ext.data.DirectStore({
            autoSave: false,
            autoLoad: false,		    
            idProperty: 'id',
            root: 'data',
            successProperty: 'success',  
            paramsAsHash: false,
            paramOrder: [ 'topType' ],
            baseParams: {
                topType: this.configuration.topType
            },
            api: {
                read: QFinance.Remoting.TopAmountPortletAction.read
            },
            fields: this.topAmountRecord,
            listeners: {
                scope: this,
                beforeload: function(store, options) {
                    this.body.mask(QFinance.loadingText, 'x-mask-loading');		
                },				
                load: function(store, records, options) {
                    this.body.unmask();
                },				
                exception: function(dataProxy, type, action, options, response, arg ) {
                    var message = '';
                    var where = '';
                    if (response.result) {
                        message = response.result.message;
                        if (response.result.type == 'exception')
                            where = response.result.where;
                    } else {
                        message = response.message;
                    }
                    this.body.unmask();
                    this.body.mask(message);					
                    QFinance.service.DeveloperService.log('Store failure: ' + message + ' where\n' + where);					
                }
            }			
        });
    },
	
    initGrid: function() {
        this.grid = new Ext.grid.GridPanel({				
            store: this.store,				
            autoHeight: true,
            columns: [
            {
                id       :'topName',
                header   : this.nameText, 
                sortable : true, 
                dataIndex: 'topName'
            },{
                id       :'amount',
                header   : this.amountText, 
                sortable : true, 
                dataIndex: 'amount',
                scope: this,
                renderer: function(value, metaData, record, rowIndex, colIndex, store) {
                    return QFinance.moneySymbol + ' ' + Ext.util.Format.number(value,QFinance.numberFormat);	            		
                }
            }],
            stripeRows: true,
            autoExpandColumn: 'topName',
            sm: new Ext.grid.RowSelectionModel()	        
        });
    },
	
    createTopAmountRecord: function() {
        this.topAmountRecord = Ext.data.Record.create([{
            name: 'topName'
        },{
            name: 'amount',	
            type: 'float'
        }]);
    },
	
    loadData: function() {
        this.setTitle(this.titleText + ' ' + this.getTopName(this.configuration.topType));
        this.store.setBaseParam('topType', this.configuration.topType);
        this.store.load();
    },
	
    onLayout: function() {
        this.grid.getView().refresh();
        QFinance.portlet.TopAmountPortlet.superclass.onLayout.call(this);
    },
	
    onRender: function(ct, position) {
        QFinance.portlet.TopAmountPortlet.superclass.onRender.call(this, ct, position);		
    },
	
    getTopName: function( topType ) {
        var topName = '';
		
        switch (parseInt(topType)) {
            case 1:
                topName = this.categoryText;
                break;
            case 2:
                topName = this.accountText;
                break;
            case 3:
                topName = this.transactionText;
                break;
            case 4:
                topName = this.markText;
                break;
        }
        return topName;
    }
});
/**
 * @depends ui.js
 */
QFinance.ui.Panel = Ext.extend( Ext.Panel, {
    constructor: function(cfg) {                        
        QFinance.ui.Panel.superclass.constructor.call(this, cfg);
    },
    
    initComponent: function() {
        QFinance.ui.Panel.superclass.initComponent.call(this);
    },
    
    getOwnerWindow: function() {
        return this.findParentByType('qwindow');
    },
    
    getProcessStatusManager: function() {
        if (!this.processStatusManager) {
            var ownerWindow = this.getOwnerWindow();
            if (ownerWindow)               
                this.processStatusManager = ownerWindow.getProcessStatusManager();
            else
                this.processStatusManager = new QFinance.ui.ProcessStatusManager();
        }
        return this.processStatusManager;
    },
    
    setProcessStatusManager: function(processStatusManager) {
        this.processStatusManager = processStatusManager;
    }
});
Ext.reg('qpanel', QFinance.ui.Panel);
/**
 * @depends ui.js, Panel.js
 */
QFinance.ui.Portal = Ext.extend(QFinance.ui.Panel, {
    layout : 'column',
    autoScroll : true,
    cls : 'x-portal',
    defaultType : 'portalcolumn',
    
    initComponent : function(){
        Ext.ux.Portal.superclass.initComponent.call(this);
        this.addEvents({
            validatedrop:true,
            beforedragover:true,
            dragover:true,
            beforedrop:true,
            drop:true
        });
    },

    initEvents : function(){
        Ext.ux.Portal.superclass.initEvents.call(this);
        this.dd = new Ext.ux.Portal.DropZone(this, this.dropConfig);
    },
    
    beforeDestroy : function() {
        if(this.dd){
            this.dd.unreg();
        }
        Ext.ux.Portal.superclass.beforeDestroy.call(this);
    }
});

Ext.reg('qportal', QFinance.ui.Portal);
/*
 * @depends component.js, Portal.js
 */
QFinance.component.OverviewPanel = Ext.extend( QFinance.ui.Portal, {
    region: 'center',
    portletsToRemove: [],
	
    // Localization
    addPortletText: 'Add portlet',
    selectPortletText: 'Select portlet',
    accountsBalanceText: 'Accounts balance',
    topAmountText: 'Top amount',
    accountsBalanceHistory: 'Accounts balance history',
    columnText: 'Column',
    addColumnText: 'Add',
    removeColumnText: 'Remove',
    saveText: 'Save',
	
    constructor: function(cfg) {
        Ext.apply(this, cfg);		
		
        QFinance.component.OverviewPanel.superclass.constructor.call(this);
    },
	
    initComponent: function() {		
        this.initButtonBar();        
        Ext.apply(this, {			
            items: []
        });
        QFinance.component.OverviewPanel.superclass.initComponent.call(this);
    },	
	
    initButtonBar: function() {
        this.tbar = {
            items: [{
                text: this.addPortletText,
                iconCls: 'puzzle--plus',
                scope: this,
                handler: function() {
                    var portletSelectWindow = new QFinance.ui.SelectWindow({
                        title: this.selectPortletText,
                        options: [
                        ['AccountsBalancePortlet', this.accountsBalanceText],
                        ['TopAmountPortlet', this.topAmountText],
                        ['AccountsBalanceHistoryPortlet', this.accountsBalanceHistory]
                        ],
                        renderTo: this.getEl(),
                        modal: true,
                        scope: this,
                        handler: function( className ) {							
                            var portlet = QFinance.portlet.PortletFactory.getPortletInstanceByClass( className );
                            if (portlet) {
                                portlet.configure(this, function() {
                                    this.addPortlet( portlet );
                                    this.doLayout();
                                }, this);
                            }
                        }
                    });
                    portletSelectWindow.show();
                }
            },{
                text: this.columnText,
                iconCls: 'layout',
                menu: {
                    xtype: 'menu',
                    style: {
                        overflow: 'visible'
                    },
                    items: [{
                        text: this.addColumnText,
                        iconCls: 'layout-split',
                        scope: this,
                        handler: function() {
                            this.addColumn();
                            this.doLayout();
                        }
                    },{
                        text: this.removeColumnText,
                        iconCls: 'layout-join',
                        scope: this,
                        handler: function() {
                            this.removeColumn();
                            this.doLayout();
                        }
                    }]
                }					
            }]			
        };		
    },
	
    initStatusBar: function(toolbar) {
        toolbar.insert(0, new Ext.Button({
            text: this.saveText,
            formBind: true,
            scope: this,
            iconCls: 'fugue-disk-black',
            handler: function() {
                this.doSave();	 
            }
        }));
    },
	
    addPortlet: function( portlet, lin, col ) {		
        this.checkCol(col == null ? 1 : col);
        if (lin == null)
            this.items.itemAt(0).add(portlet);
        else 
            this.items.itemAt(col-1).insert(lin-1, portlet);	
    },
	
    addColumn: function() {							
        this.add(new Ext.ux.PortalColumn({
            columnWidth: 0,
            style: 'padding: 10px'
        }));
        this.resizeColumns();
    },
	
    removeColumn: function() {
        if (this.items.getCount() > 1) {
            var lastColumn = this.items.last();
            var targetColumn = this.items.itemAt(this.items.getCount()-2);
            lastColumn.items.each(function(item) {
                targetColumn.add(item);
            });
            this.remove(lastColumn);
            this.resizeColumns();
        }
    },
	
    resizeColumns: function() {
        var columns = this.items.getCount();
        this.items.each(function(item) {
            item.columnWidth = (100/columns)/100;
        });		
    },
	
    checkCol: function(col) {		
        var diff = col - this.items.getCount();
        for (var i = 1; i <= diff; i++ ) {
            this.addColumn();
        }
    },
	
    loadPortlets: function() {		
        var loadPortletsID = this.getProcessStatusManager().start([this]);
        QFinance.Remoting.OverviewPanelAction.getPortlets(function(result, event) {
            var message = '';
            var where = '';
            var failure = false;
			
            if (result) {
                if (result.success) {					
                    for (var i = 0; i < result.data.length; i++) {
                        var portlet = QFinance.portlet.PortletFactory.getPortletInstanceByClass( result.data[i].className );
                        if (portlet) {
                            portlet.internalID = result.data[i].id;
                            portlet.configuration = result.data[i].configuration && result.data[i].configuration;	
                            this.addPortlet(portlet, result.data[i].lin, result.data[i].col );
                            this.doLayout();
                            portlet.loadData();
                        }
                    }
                    this.getProcessStatusManager().success(loadPortletsID);
                } else {
                    failure = true;						
                    message = result.message;
                    if (result.type == 'exception')
                        where = result.where;
                }            
            } else {
                failure = true;
                message = event.message;
            }
			
            if (failure) {
                this.getProcessStatusManager().error(loadPortletsID, message);                
                QFinance.service.DeveloperService.log('Direct call failure: ' + message + ' where\n' + where);				
            }
			
        }, this);		
    },
	
    doSave: function() {
        var doSaveID = this.getProcessStatusManager().start([this]);
        var portlets = [];
		
        for (var col = 0; col < this.items.getCount(); col++) {
            for (var lin = 0; lin < this.items.itemAt(col).items.getCount(); lin++) {
                portlets.push( {
                    internalID: this.items.itemAt(col).items.itemAt(lin).internalID,
                    className: this.items.itemAt(col).items.itemAt(lin).className,
                    configuration: this.items.itemAt(col).items.itemAt(lin).configuration,
                    col: col + 1,
                    lin: lin + 1
                });
            }
        }
        QFinance.Remoting.OverviewPanelAction.savePortlets(portlets, this.portletsToRemove, function(result, event) {
            var message = '';
            var where = '';
            var failure = false;
			
            if (result) {
                if (result.success) {
                    this.getProcessStatusManager().success(doSaveID);                    
                } else {
                    failure = true;						
                    message = result.message;
                    if (result.type == 'exception')
                        where = result.where;
                }            
            } else {
                failure = true;
                message = event.message;
            }
			
            if (failure) {
                this.getProcessStatusManager().success(doSaveID, message);
                QFinance.service.DeveloperService.log('Direct call failure: ' + message + ' where\n' + where);
            }
			
            this.portletsToRemove = [];
        }, this);
    },
	
    markToRemove: function(portlet) {		
        this.portletsToRemove.push(portlet.internalID);
    }
});
Ext.reg('QFinance.component.OverviewPanel', QFinance.component.OverviewPanel);
/*
 * @depends component.js, Panel.js
 */
QFinance.component.AccountsEditPanel = Ext.extend( QFinance.ui.Panel, {
    // Configuration
    autoLoadAccounts: true,
    canAddAccount: true,
    canEditAccount: true,
    canRemoveAccount: true,
	
    // Localization	
    addAccountText: 'Add',
    addAccountTooltipText: 'Add a new account',
    editAccountText: 'Edit',
    editAccountTooltipText: 'Edit account',
    removeAccountText: 'Remove',
    removeAccountTooltipText: 'Remove account',
    accountText: 'Account',
    bankNumberText: 'Bank number',
    bankAgencyText: 'Bank agency',
    bankAccoutText: 'Bank account',
    initialAmountText: 'Initial amount',
    accountTypeNameText: 'Type',
    removeQuestionTitle: 'Remove account',
    removeQuestionMsg: 'Would you like to remove selected accounts?',
    editInformationTitle: 'Edit account',
    editInformationMsg: 'Please select an account to edit.',
    removeInformationTitle: 'Remove account',
    removeInformationMsg: 'Please select an account to remove.',	
	
    // Components
    store: null,		
    grid: null,
    accountRecord: null,	
	
    constructor: function(config) {
        Ext.apply(this, config);
		
        this.createAccountRecord();
		
        this.store = new Ext.data.DirectStore({
            autoSave: false,
            autoLoad: false,
            idProperty: 'id',
            root: 'data',
            successProperty: 'success',
            paramsAsHash: false,    		
            api: {
                read: QFinance.Remoting.AccountsEditPanelAction.read,
                create: QFinance.Remoting.AccountsEditPanelAction.create,
                update: QFinance.Remoting.AccountsEditPanelAction.update,
                destroy: QFinance.Remoting.AccountsEditPanelAction.destroy
            },
            writer: new Ext.data.JsonWriter({
                encode: false,
                writeAllFields: true
            }),			
            fields: this.accountRecord,
            listeners: {
                scope: this,
                beforeload: function(store, options) {
                    store.id = this.getProcessStatusManager().start([this]);
                },				
                load: function(store, records, options) {
                    this.getProcessStatusManager().success(store.id);
                },
                beforewrite: function(  store, action, rs, options, arg ) {
                    store.id = this.getProcessStatusManager().start([this]);
                },
                write: function(  store, action, rs, options, arg ) {
                    this.getProcessStatusManager().success(store.id);
                },				
                exception: function(dataProxy, type, action, options, response, arg ) {
                    var message = '';
                    var where = '';
                    if (response.result) {
                        message = response.result.message;
                        if (response.result.type == 'exception')
                            where = response.result.where;
                    } else {
                        message = response.message;
                    }
                    this.getProcessStatusManager().success(this.store.id, message);                    
                    QFinance.service.DeveloperService.log('Store failure: ' + message + ' where\n' + where);					
                }
            }
        });
		
        this.addEvents([ 
            'close'
            ]);		
		
        QFinance.component.AccountsEditPanel.superclass.constructor.call(this);
    },
	
    initComponent: function() {		
        var topBarConfig = this.getTopBarConfig();		
        var topBar = new Ext.Toolbar(topBarConfig);
        var gridConfig = this.getGridConfig(topBar);
        this.grid = new Ext.grid.GridPanel(gridConfig);
				
        Ext.apply(this,{
            layout: 'fit',			
            items: [this.grid]
        });

        QFinance.component.AccountsEditPanel.superclass.initComponent.call(this);
    },
	
    createAccountRecord: function() {
        this.accountRecord = Ext.data.Record.create([{
            name: 'id',
            type: 'int'
        },{
            name: 'accountName'
        },{
            name: 'bankNumber'
        },{
            name: 'bankAccount'															
        },{
            name: 'accountType',
            type: 'int'
        },{
            name: 'accountTypeName'
        },{
            name: 'initialAmount',
            type: 'float'															
        },{
            name: 'bankAgency'
        }]);
    },
	
    getTopBarConfig: function() {
        var topBarConfig = [];
				
        if (this.canAddAccount) {
            topBarConfig.push({
                text: this.addAccountText,
                tooltip: this.addAccountTooltipText,
                iconCls: 'fugue-wallet--plus',
                scope: this,
                handler: function() {
                    var baseRecordConfig = {
                    }; 
										
                    var newAccount = new QFinance.component.AccountEditWindow({
                        ownerWindow: this.getOwnerWindow(),
                        record: new this.accountRecord(baseRecordConfig),
                        listeners: {
                            scope: this,
                            save: function( record ) {
                                this.store.add( record );
                                this.doSave();								
                            }
                        }
                    });
                    newAccount.show();
                }
            });
        }
		
        if (this.canEditAccount) {
            topBarConfig.push({
                text: this.editAccountText,
                tooltip: this.editAccountTooltipText,
                iconCls: 'fugue-wallet--pencil',
                scope: this,
                handler: function() {
                    var selectedRecord = this.grid.getSelectionModel().getSelected();
					
                    if (selectedRecord) {
                        var editAccount = new QFinance.component.AccountEditWindow({
                            ownerWindow: this.getOwnerWindow(),
                            record: selectedRecord,
                            isNew: false,
                            autoLoadRecord: true,							
                            listeners: {
                                scope: this,
                                save: function(record) {
                                    this.doSave();
                                }
                            }
                        });
                        editAccount.show();
                    } else {
                        var information = new QFinance.ui.MessageBox();
                        information.show({
                            title: this.editInformationTitle,
                            msg: this.editInformationMsg,
                            buttons: Ext.MessageBox.OK,
                            renderTo: this.body,
                            icon: Ext.MessageBox.INFO
                        });
                    }
                }
            });
        }
		
        if (this.canRemoveAccount) {
            topBarConfig.push({
                text: this.removeAccountText,
                tooltip: this.removeAccountTooltipText,
                iconCls: 'fugue-wallet--minus',
                scope: this,
                handler: function() {
                    var selectedRecords = this.grid.getSelectionModel().getSelections();
					
                    if (selectedRecords.length > 0) {
                        var question = new QFinance.ui.MessageBox();
                        question.show({
                            title: this.removeQuestionTitle,
                            msg: this.removeQuestionMsg,
                            buttons: Ext.MessageBox.YESNO,
                            scope: this,
                            fn: function(btn) {
                                if (btn == 'yes') {
                                    for (var i = 0; i < selectedRecords.length; i++)
                                        this.store.remove( selectedRecords[i] );
                                    this.doSave();
                                }								   
                            },
                            renderTo: this.body,
                            icon: Ext.MessageBox.QUESTION
                        });
                    } else {
                        var information = new QFinance.ui.MessageBox();
                        information.show({
                            title: this.removeInformationTitle,
                            msg: this.removeInformationMsg,
                            buttons: Ext.MessageBox.OK,
                            renderTo: this.body,
                            icon: Ext.MessageBox.INFO
                        });						
                    }
                }
            });
        }
		
        return topBarConfig;
    },
	
    getGridConfig: function(topBar) {
        var gridConfig = {
            store: this.store,			
            columns: [
            {
                id			: 'accountName',
                header		: this.accountText, 
                sortable	: true,
                dataIndex	: 'accountName'	            
            },{
                id			: 'bankNumber',
                header		: this.bankNumberText, 
                sortable	: true,
                dataIndex	: 'bankNumber',
                width		: 80
            },{
                id			: 'bankAgency',
                header		: this.bankAgencyText, 
                sortable	: true,
                dataIndex	: 'bankAgency',
                width		: 80
            },{
                id			: 'bankAccount',
                header		: this.bankAccoutText,
                sortable	: true,
                dataIndex	: 'bankAccount',
                width		: 80
            },{
                id			: 'initialAmount',
                header		: this.initialAmountText, 
                sortable	: true,
                dataIndex	: 'initialAmount',
                scope		: this,
                renderer: function(value, metaData, record, rowIndex, colIndex, store) {	            	
                    return '<span style="color:green;">' + QFinance.moneySymbol + ' ' + Ext.util.Format.number(value,QFinance.numberFormat) + '</span>';	            	
                },
                width		: 80	            
            },{
                id			: 'accountTypeName',
                header		: this.accountTypeNameText, 
                sortable	: true,
                dataIndex	: 'accountTypeName',
                width		: 50
            }],
            stripeRows: true,
            autoExpandColumn: 'accountName',
            sm: new Ext.grid.RowSelectionModel(),
            tbar: topBar,
            stateful: true,
            stateid: 'QFinance.component.AccountsEditPanel.grid'
        };
		
        return gridConfig;
    },
		
    doSave: function() {
        this.store.save();
    },
        
    autoLoadData: function() {
        if (this.autoLoadAccounts)
            this.load();
    },
	
    load: function() {
        this.store.load();
    }
});
Ext.reg('QFinance.component.AccountsEditPanel', QFinance.component.AccountsEditPanel);
/*
 * @depends component.js, Panel.js
 */
QFinance.component.CategoriesEditPanel = Ext.extend( QFinance.ui.Panel, {
    // Configuration
    layout: 'fit',
    canAddCategory: true,
    canEditCategory: true,
    canRemoveCategory: true,
    categoryRecord: null,
    autoSelectCategoryID: null,
    selectingCategory: false,
	
    // Localization
    addCategoryText: 'Add',
    addCategoryToolTipText: 'Add a new category',
    editCategoryText: 'Edit',
    editCategoryToolTipText: 'Edit selected category',
    removeCategoryText: 'Remove',
    removeCategoryToolTipText: 'Remove selected category',
    categoriesText: 'Categories',
    removeQuestionTitle: 'Remove category',
    removeQuestionMsg: 'Would you like to remove selected accounts?',
    editInformationTitle: 'Edit account',	
    editInformationMsg: 'Please select a category to edit.',    
    addInformationTitle: 'Add category',
    addInformationMsg: 'Please select a category or root node.',
    removeInformationTitle: 'Remove category',
    removeInformationMsg: 'Please select a category to remove.',
	
    // IDs    
    selectCategoryIDID: null,
	
    // Components
    treePanel: null,
	
    constructor: function(config) {
        Ext.apply(this, config);
		
        this.createCategoryRecord();
        
        this.treeLoaderIDs = [];
		
        QFinance.component.CategoriesEditPanel.superclass.constructor.call(this);
    },
	
    initComponent: function() {
        var treePanelConfig = this.getTreePanelConfig();
		
        this.treePanel = new Ext.tree.TreePanel(treePanelConfig);				
        this.items = [ this.treePanel ];		
		
        if (this.canAddCategory || this.canEditCategory || this.canRemoveCategory)
            Ext.apply(this,{
                tbar: this.getTopBarConfig()
            });
		
        QFinance.component.CategoriesEditPanel.superclass.initComponent.call(this);
    },
	
    getTopBarConfig: function() {
        var topBarConfig = {
            items: this.getTopBarItemsConfig()	
        };		
		
        return topBarConfig;
    },
		
    getTopBarItemsConfig: function() {
        var topBarItemsConfig = [];
		
        if (this.canAddCategory) {
            topBarItemsConfig.push({
                text: this.addCategoryText,
                tooltip: this.addCategoryToolTipText,
                iconCls: 'fugue-plus-circle',
                scope: this,
                handler: function() {
                    var selectedNode = this.treePanel.getSelectionModel().getSelectedNode();                        	                    	
                    if (selectedNode) {
                        var parentCategoryID = selectedNode.id == 'root' ? null : selectedNode.id;
                        var category = new this.categoryRecord({
                            parentCategoryID: parentCategoryID
                        });
                        var newCategory = new QFinance.component.CategoryEditWindow({
                            renderTo: this.getEl(),
                            constrain: true,
                            modal: true,                		
                            record: category,
                            autoLoadRecord: true,
                            listeners: {
                                scope: this,
                                save: function(record) {
                                    this.createCategory(record);
                                }
                            }
                        });
                        newCategory.show();
                    } else {
                        var information = new QFinance.ui.MessageBox();
                        information.show({
                            title: this.addInformationTitle,
                            msg: this.addInformationMsg,
                            buttons: Ext.MessageBox.OK,
                            renderTo: this.body,
                            icon: Ext.MessageBox.INFO
                        });
                    }              	
                }
            });
        }
		
        if (this.canEditCategory) {
            topBarItemsConfig.push({
                text: this.editCategoryText,
                tooltip: this.editCategoryToolTipText,
                iconCls: 'fugue-pencil',
                scope: this,
                handler: function() {
                    var selectedNode = this.treePanel.getSelectionModel().getSelectedNode();                        	                    	
                    if (selectedNode && selectedNode.parentNode ) {
                        var category = this.loadCategoryFromNode( selectedNode );                		
                        var editCategory = new QFinance.component.CategoryEditWindow({
                            renderTo: this.getEl(),
                            constrain: true,
                            modal: true,                		
                            record: category,
                            autoLoadRecord: true,
                            isNew: false,
                            listeners: {
                                scope: this,
                                save: function(record) {
                                    this.updateCategory(record);
                                }
                            }
                        });
                        editCategory.show();
                    } else {
                        var information = new QFinance.ui.MessageBox();
                        information.show({
                            title: this.editInformationTitle,
                            msg: this.editInformationMsg,
                            buttons: Ext.MessageBox.OK,
                            renderTo: this.body,
                            icon: Ext.MessageBox.INFO
                        });
                    }               	
                }
            });
        }
		
        if (this.canRemoveCategory) {
            topBarItemsConfig.push({
                text: this.removeCategoryText,
                tooltip: this.removeCategoryToolTipText,
                iconCls: 'fugue-minus-circle',
                scope: this,
                handler: function() {
                    var selectedNode = this.treePanel.getSelectionModel().getSelectedNode();                        	                    	
                    if (selectedNode && selectedNode.parentNode ) {
                        var category = this.loadCategoryFromNode( selectedNode );                		
                        this.destroyCategory( category );
                    } else {
                        var information = new QFinance.ui.MessageBox();
                        information.show({
                            title: this.removeInformationTitle,
                            msg: this.removeInformationMsg,
                            buttons: Ext.MessageBox.OK,
                            renderTo: this.body,
                            icon: Ext.MessageBox.INFO
                        });
                    }
                }
            });
        }
		
        return topBarItemsConfig;
    },
	
    getTreePanelConfig: function() {
        var treePanelConfig = {
            enableDD: true,
            autoScroll: true,
            root: {
                id: 'root',
                text: this.categoriesText
            },
            loader: new Ext.tree.TreeLoader({
                directFn: QFinance.Remoting.CategoriesEditPanelAction.getCategoryTree,
                listeners: {
                    scope: this,
                    beforeload: function(treeLoader, node, callback) {
                        treeLoader.failure = false;
                        this.treeLoaderIDs.push(this.getProcessStatusManager().start([this]));
                    },
                    load: function(treeLoader, node, response) {
                        if (!treeLoader.failure) {
                            this.getProcessStatusManager().success(this.treeLoaderIDs.pop());                            
                            this.getProcessStatusManager().success(this.selectCategoryIDID);
                        }
                    },
                    loadexception: function(treeLoader, node, response) {
                        treeLoader.failure = true;
                        var message = '';
                        var where = '';
                        if (response.responseText) {
                            message = response.responseText.message;
                            if (response.responseText.type == 'exception')
                                where = response.responseText.where;
                        } else {
                            message = 'Unable to connect to the server.';
                        }
                        this.getProcessStatusManager().error(this.treeLoaderIDs.pop(), message);                        
                        this.getProcessStatusManager().error(this.selectCategoryIDID, message);                          
                        QFinance.service.DeveloperService.log('TreeLoader failure: ' + message + ' where\n' + where);
                    }
                }
            }),	        
            dropConfig: {
                allowParentInsert: true
            },
            listeners: {
                scope: this,
                beforemovenode: this.beforeMoveNode,
                movenode: this.moveNode
            }
        };
		
        return treePanelConfig;
    },
	
    beforeMoveNode: function() {
        return this.canEditCategory;
    },
	
    moveNode: function(tree, node, oldParent, newParent, index) {
        var moveNodeID = this.getProcessStatusManager().start([this.treePanel]);
        var callback = function(result, event) {
            var message = '';
            var where = '';
            var failure = false;
			
            if (result) {
                if (result.success) {
                    this.getProcessStatusManager().success(moveNodeID);
                } else {
                    failure = true;						
                    message = result.message;
                    if (result.type == 'exception')
                        where = result.where;
                }            
            } else {
                failure = true;
                message = event.message;
            }
			
            if (failure) {
                this.getProcessStatusManager().error(moveNodeID, message);                
                QFinance.service.DeveloperService.log('Direct call failure: ' + message + ' where\n' + where);
                this.treePanel.getRootNode().reload();
            }            
        };                			
				
        if (newParent.id == 'root')
            QFinance.Remoting.CategoriesEditPanelAction.clearParentCategory( node.id, callback, this );
        else
            QFinance.Remoting.CategoriesEditPanelAction.setParentCategory( node.id, newParent.id, callback, this );		
    },
	
    createCategoryRecord: function() {
        this.categoryRecord = Ext.data.Record.create([
        {
            name: 'id', 
            type: 'int'
        },
        {
            name: 'categoryName', 
            allowBlank: false
        },
        {
            name: 'parentCategoryID', 
            type: 'int'
        }
        ]);
    },
	
    createCategory: function( record ) {
        var createCategoryID = this.getProcessStatusManager().start(this.treePanel);        
        QFinance.Remoting.CategoriesEditPanelAction.create(record, function(result, event) {
            var message = '';
            var where = '';
            var failure = false;
			
            if (result) {
                if (result.success) {
                    this.getProcessStatusManager().success(createCategoryID);
                    var selectedNode = this.treePanel.getSelectionModel().getSelectedNode();                        	                    	
                    if (selectedNode) {
                        selectedNode.reload(function() {
                            var node = this.treePanel.getNodeById(result.id);
                            node.select();
                        }, this);
                    }		
                } else {
                    failure = true;						
                    message = result.message;
                    if (result.type == 'exception')
                        where = result.where;
                }            
            } else {
                failure = true;
                message = event.message;
            }
			
            if (failure) {
                this.getProcessStatusManager().error(createCategoryID, message);                
                QFinance.service.DeveloperService.log('Direct call failure: ' + message + ' where\n' + where);
            }
        }, this);
    },
	
    updateCategory: function( record ) {
        var updateCategoryID = this.getProcessStatusManager().start([this.treePanel]);
        QFinance.Remoting.CategoriesEditPanelAction.update(record, function(result, event) {
            var message = '';
            var where = '';
            var failure = false;
			
            if (result) {
                if (result.success) {
                    this.getProcessStatusManager().success(updateCategoryID);                    
                    var selectedNode = this.treePanel.getSelectionModel().getSelectedNode();                        	                    	
                    if (selectedNode) {
                        selectedNode.parentNode.reload(function() {
                            var node = this.treePanel.getNodeById(record.get('id'));
                            node.select();
                        }, this);            		
                    }		
                } else {
                    failure = true;						
                    message = result.message;
                    if (result.type == 'exception')
                        where = result.where;
                }            
            } else {
                failure = true;
                message = event.message;
            }
			
            if (failure) {
                this.getProcessStatusManager().error(updateCategoryID, message);                
                QFinance.service.DeveloperService.log('Direct call failure: ' + message + ' where\n' + where);
            }      
        }, this);		
    },
	
    destroyCategory: function( record ) {
        var question = new QFinance.ui.MessageBox();
        question.show({
            title: this.removeQuestionTitle,
            msg: this.removeQuestionMsg,
            buttons: question.YESNO,
            icon: question.QUESTION,
            scope: this,
            fn: function(btn) {
                if (btn == 'yes') {
                    var destroyCategoryID = this.getProcessStatusManager().start([this.treePanel]);
                    QFinance.Remoting.CategoriesEditPanelAction.destroy(record, function(result, event) {
                        var message = '';
                        var where = '';
                        var failure = false;
						
                        if (result) {
                            if (result.success) {
                                this.getProcessStatusManager().success(destroyCategoryID);
                                var selectedNode = this.treePanel.getSelectionModel().getSelectedNode();                        	                    	
                                if (selectedNode) {
                                    selectedNode.parentNode.reload();            		
                                }		
                            } else {
                                failure = true;						
                                message = result.message;
                                if (result.type == 'exception')
                                    where = result.where;
                            }            
                        } else {
                            failure = true;
                            message = event.message;
                        }
						
                        if (failure) {
                            this.getProcessStatusManager().error(destroyCategoryID, message);                            
                            QFinance.service.DeveloperService.log('Direct call failure: ' + message + ' where\n' + where);
                        }    
                    }, this);	
                }								   
            },
            renderTo: this.body					   
        });
    },
	
    loadCategoryFromNode: function( node ) {
        var parentCategoryID = node.parentNode.id == 'root' ? null : node.parentNode.id;
        var category = new this.categoryRecord({
            id: node.id,
            categoryName: node.text,
            parentCategoryID: parentCategoryID
        });
		
        return category;
    },
	
    getSelectedCategory: function() {
        var selectedNode = this.treePanel.getSelectionModel().getSelectedNode();                        	                    	
        if (selectedNode) {
            if (selectedNode.parentNode)
                return this.loadCategoryFromNode(selectedNode);
        }
        return null;
    },
	
    selectCategoryID: function( categoryID ) {
        var categoryFound = false;

        this.treePanel.on('expandnode', function(node) {
            if (node.id == categoryID) {
                node.selectSilent();
                categoryFound = true;
            }
        }, this);
        
        var checkFunction = function() {
            if (categoryFound) {
                this.treePanel.un('beforeload', checkFunction, this);
                return false;
            } else {
                return true;
            }
        }; 
        this.treePanel.on('beforeload', checkFunction, this);       
        this.treePanel.root.expand(true);
    },
	
    onRender: function(ct, position) {
        QFinance.component.CategoriesEditPanel.superclass.onRender.call(this,ct, position);
        if (this.autoSelectCategoryID)
            this.selectCategoryID( this.autoSelectCategoryID );		
    }
});
Ext.reg('QFinance.component.CategoriesEditPanel', QFinance.component.CategoriesEditPanel);
/*
 * @depends component.js, Panel.js
 */
QFinance.component.ExpensesAndIncomesByCategoryPanel = Ext.extend( QFinance.ui.Panel, {
    // Localization
    updateText: 'Update',
    optionsText: 'Options',
    accountText: 'Account',
    allTimeText: 'All time',
    past30DaysText: 'Past 30 days',
    past60DaysText: 'Past 60 days',
    thisMonthText: 'This month',
    thisYearText: 'This year',
    customText: 'Custom',
    rangeText: 'Range',
    bothText: 'Both',
    incomeText: 'Income',
    expenseText: 'Expense',
    typeText: 'Type',
    emptyResultText: 'There are no transactions within the chosen options',
	
    // Components
    store: null,
    accountsStore: null,
    rangeCompositeField: null,
    formPanel: null,
    categoriesEditPanel: null,
    accountCombo: null,
    rangeCombo: null,
    typeCombo: null,
	
    constructor: function(config) {
        Ext.apply(this, config);
		
        this.store = new Ext.data.DirectStore({
            autoLoad: false,
            idProperty: 'id',
            root: 'data',
            successProperty: 'success',
            paramsAsHash: false,
            paramOrder: [ 'options', 'accountID', 'parentCategoryID' ],
            baseParams: {
                options: null, 
                accountID: null, 
                parentCategoryID: null
            },
            api: {
                read: QFinance.Remoting.ExpensesAndIncomesByCategoryPanelAction.getExpensesAndIncomesByCategory
            },
            fields: [
            'categoryName',
            'value'
            ],
            listeners: {
                scope: this,
                beforeload: function(store, options) {
                    store.id = this.getProcessStatusManager().start([this]);
                },				
                load: function(store, records, options) {					
                    if (records.length == 0) {
                        this.getProcessStatusManager().success(store.id, this.emptyResultText);
                    } else {
                        this.getProcessStatusManager().success(store.id);
                    }
                },				
                exception: function(dataProxy, type, action, options, response, arg ) {
                    var message = '';
                    var where = '';
                    if (response.result) {
                        message = response.result.message;
                        if (response.result.type == 'exception')
                            where = response.result.where;
                    } else {
                        message = response.message;
                    }
                    this.getProcessStatusManager().error(this.store.id, message);
                    QFinance.service.DeveloperService.log('Store failure: ' + message + ' where\n' + where);
                }
            }				
        });
		
        this.accountStore = new Ext.data.DirectStore({    		
            autoLoad: false,
            directFn: QFinance.Remoting.AccountAction.getByAccountTypePlusAll,
            paramsAsHash: false,            
            idProperty: 'id',
            root: 'data',
            successProperty: 'success',
            paramOrder: [ 'type' ],
            baseParams: {
                type: '1'
            },
            fields: [
            {
                name: 'id',
                type: 'int',
                useNull: true
            },
            {
                name: 'accountName'	    		    
            },
            {
                name: 'accountType'
            }
            ],
            listeners: {
                scope: this,
                beforeload: function(store, options) {
                    store.id = this.getProcessStatusManager().start([this.accountCombo]);                    
                },				
                load: function(store, records, options) {
                    this.getProcessStatusManager().success(store.id);
                    this.accountCombo.setValue(this.accountCombo.store.getAt(0).get(this.accountCombo.id));	
                },				
                exception: function(dataProxy, type, action, options, response, arg ) {
                    var message = '';
                    var where = '';
                    if (response.result) {
                        message = response.result.message;
                        if (response.result.type == 'exception')
                            where = response.result.where;
                    } else {
                        message = response.message;
                    }
                    this.getProcessStatusManager().error(this.accountStore.id, message);
                    QFinance.service.DeveloperService.log('Store failure: ' + message + ' where\n' + where);
                }
            }		
        });		
		
        QFinance.component.ExpensesAndIncomesByCategoryPanel.superclass.constructor.call(this);
    },
	
    initComponent: function() {	
        Ext.apply(this, {
            layout: 'border',
            items: [{
                region: 'north',
                collapsible: true,				
                layout: 'hbox',
                title: this.optionsText,				
                height: 150,
                layoutConfig: {
                    align : 'stretch',
                    pack  : 'start'
                },				
                items: [ this.formPanel = new Ext.form.FormPanel({
                    xtype: 'form',
                    flex: 1,						
                    frame: true,
                    labelWidth: 60,
                    defaults: {
                        anchor: '100%'
                    },
                    items: [ this.accountCombo = new Ext.form.ComboBox({
                        name: 'accountID',
                        store: this.accountStore,
                        fieldLabel: this.accountText,
                        autoSelect: true,
                        editable: false,
                        triggerAction: 'all',		      		    
                        valueField: 'id',
                        displayField: 'accountName',
                        mode: 'local',
                        listeners: {
                            scope: this,
                            select: function(combo, record, index) {
                                this.typeCombo.setDisabled( index == 0 );		              				
                            }
                        }
                    }), this.rangeCombo = new Ext.form.ComboBox({			        	
                        name: 'range',
                        store: [ 
                        [ 1, this.allTimeText ],
                        [ 2, this.past30DaysText ],
                        [ 3, this.past60DaysText ],
                        [ 4, this.thisMonthText ],
                        [ 5, this.thisYearText ],
                        [ 6, this.customText ]
                        ],
                        fieldLabel: this.rangeText,
                        autoSelect: true,		            	
                        editable: false,
                        triggerAction: 'all',		      		    		              	
                        mode: 'local',
                        hiddenName: 'range',
                        value: 1,
                        listeners: {
                            scope: this,
                            select: function(combo, record, index) {		              					              			
                                if (index != 5)
                                    this.rangeCompositeField.items.each(function(f){
                                        f.clearInvalid();
                                    });
		              				
		              			
                                this.rangeCompositeField.setDisabled( index != 5 );
                            }
                        }
                    }), this.rangeCompositeField = new Ext.form.CompositeField({
                        xtype: 'compositefield',
                        disabled: true,
                        defaults: {
                            flex: 1
                        },
                        items: [{
                            xtype: 'datefield',
                            name: 'startDate',
                            id: 'startDate',
                            format: "Y-m-d",
                            vtype: 'daterangecomposite',
                            endDateField: 'endDate',
                            allowBlank: false
                        },
                        {
                            xtype: 'datefield',
                            name : 'endDate',
                            id: 'endDate',
                            format: "Y-m-d",
                            vtype: 'daterangecomposite',
                            startDateField: 'startDate',
                            allowBlank: false
                        }]
                    }), this.typeCombo = new Ext.form.ComboBox({			        	
                        name: 'type',
                        store: [ 
                        [ 1, this.bothText ],
                        [ 2, this.incomeText ],
                        [ 3, this.expenseText ]
                        ],
                        disabled: true,
                        fieldLabel: this.typeText,
                        autoSelect: true,		            	
                        editable: false,
                        triggerAction: 'all',		      		    		              	
                        mode: 'local',
                        hiddenName: 'type',
                        value: 1
                    })]					
                }),this.categoriesEditPanel = new QFinance.component.CategoriesEditPanel({					
                    canAddCategory: false,
                    canEditCategory: false,
                    canRemoveCategory: false,
                    flex: 1,                    
                    statusBar: this.statusBar
                })]
            },{
                xtype: 'highchart',
                store: this.store,
                region: 'center',
                series: [{
                    type: 'pie',
                    dataField: 'value',
                    categorieField: 'categoryName'
                }],
                chartConfig: {
                    chart: {
						
                    },
                    plotOptions: {
                        pie: {
                            allowPointSelect: false,
                            cursor: 'pointer',
                            dataLabels: {
                                enabled: true,				                
                                formatter: function() {
                                    return '<b>'+ this.point.name +'</b>: '+ QFinance.moneySymbol + ' ' + Ext.util.Format.number(this.y,QFinance.numberFormat) + ' (' + this.percentage.toFixed(2) + '%)';
                                }
                            }
                        }
                    },
                    title: {
                        text: null
                    },
                    credits: {
                        enabled: false
                    },
                    tooltip: {
                        enabled: false
                    }
                }
            }]
        });		
        QFinance.component.ExpensesAndIncomesByCategoryPanel.superclass.initComponent.call(this);
    },
    
    initStatusBar: function(toolbar) {            	
        toolbar.insert(0, new Ext.Button({
            text: this.updateText,
            scope: this,
            iconCls: 'fugue-arrow-circle',
            handler: function() {
                this.update();
            }
        }));
    },
	
    update: function(scope, callback) {
        if (this.formPanel.getForm().isValid()) {			
            var options = {
                range: this.rangeCombo.getValue(),
                type: this.typeCombo.getValue()
            };
			
            if (options.range == 6) {
                options.startDate = this.formPanel.getForm().findField('startDate').getValue();
                options.endDate = this.formPanel.getForm().findField('endDate').getValue();
            }
			
            var parentCategoryID = null;
            var selectedCategory = this.categoriesEditPanel.getSelectedCategory();
            if (selectedCategory)
                parentCategoryID = selectedCategory.get('id'); 
			
            this.store.setBaseParam('options', options);
            if (this.accountCombo.getValue() > 0)
                this.store.setBaseParam('accountID', this.accountCombo.getValue());
            else
                this.store.setBaseParam('accountID', null);
			
            this.store.setBaseParam('parentCategoryID', parentCategoryID);
            this.store.load({
                scope: scope || null,
                callback: callback || null
            });
        }
    },
    
    autoLoadData: function() {        
        this.body.mask();
        this.accountStore.load({
            scope: this,
            callback: function() {                
                this.update(this, function() {
                    this.categoriesEditPanel.selectCategoryID('root');
                    this.body.unmask();
                });
            } 
        }, this);        
    }
});
Ext.reg('QFinance.component.ExpensesAndIncomesByCategoryPanel', QFinance.component.ExpensesAndIncomesByCategoryPanel);
/*
 * @depends component.js, Panel.js
 */
QFinance.component.MarksEditPanel = Ext.extend( QFinance.ui.Panel, {
    // Configuration
    canAdd: true,
    canEdit: true,
    canRemove: true,
	
    // Localization	
    addText: 'Add',
    addTooltipText: 'Add a new mark',
    editText: 'Edit',
    editTooltipText: 'Edit mark',
    removeText: 'Remove',
    removeTooltipText: 'Remove mark',
    markText: 'Mark',
    descriptionText: 'Description',    
    removeQuestionTitle: 'Remove mark',
    removeQuestionMsg: 'Would you like to remove selected marks?',
    editInformationTitle: 'Edit mark',
    editInformationMsg: 'Please select an mark to edit.',
    removeInformationTitle: 'Remove mark',
    removeInformationMsg: 'Please select an mark to remove.',	
	
    // Components
    store: null,		
    grid: null,
    record: null,	
	
    constructor: function(config) {
        Ext.apply(this, config);
		
        this.createRecord();
		
        this.store = new Ext.data.DirectStore({
            autoSave: false,
            autoLoad: false,
            idProperty: 'id',
            root: 'data',
            successProperty: 'success',
            paramsAsHash: false,    		
            api: {
                read: QFinance.Remoting.MarksEditPanelAction.read,
                create: QFinance.Remoting.MarksEditPanelAction.create,
                update: QFinance.Remoting.MarksEditPanelAction.update,
                destroy: QFinance.Remoting.MarksEditPanelAction.destroy
            },
            writer: new Ext.data.JsonWriter({
                encode: false,
                writeAllFields: true
            }),			
            fields: this.record,
            listeners: {
                scope: this,
                beforeload: function(store, options) {
                    store.id = this.getProcessStatusManager().start([this]);
                },				
                load: function(store, records, options) {
                    this.getProcessStatusManager().success(store.id);
                },
                beforewrite: function(  store, action, rs, options, arg ) {
                    store.id = this.getProcessStatusManager().start([this]);
                },
                write: function(  store, action, rs, options, arg ) {
                    this.getProcessStatusManager().success(store.id);
                },				
                exception: function(dataProxy, type, action, options, response, arg ) {
                    var message = '';
                    var where = '';
                    if (response.result) {
                        message = response.result.message;
                        if (response.result.type == 'exception')
                            where = response.result.where;
                    } else {
                        message = response.message;
                    }
                    this.getProcessStatusManager().success(this.store.id, message);                    
                    QFinance.service.DeveloperService.log('Store failure: ' + message + ' where\n' + where);					
                }
            }
        });
		
        this.addEvents([ 
            'close'
            ]);		
		
        QFinance.component.MarksEditPanel.superclass.constructor.call(this);
    },
	
    initComponent: function() {		
        var topBarConfig = this.getTopBarConfig();		
        var topBar = new Ext.Toolbar(topBarConfig);
        var gridConfig = this.getGridConfig(topBar);
        this.grid = new Ext.grid.GridPanel(gridConfig);
				
        Ext.apply(this,{
            layout: 'fit',			
            items: [this.grid]
        });

        QFinance.component.MarksEditPanel.superclass.initComponent.call(this);
    },
	
    createRecord: function() {
        this.record = Ext.data.Record.create([{
            name: 'id',
            type: 'int'
        },{
            name: 'name'
        },{
            name: 'description'
        }]);
    },
	
    getTopBarConfig: function() {
        var topBarConfig = [];
				
        if (this.canAdd) {
            topBarConfig.push({
                text: this.addText,
                tooltip: this.addTooltipText,
                iconCls: 'fugue-bookmark--plus',
                scope: this,
                handler: function() {
                    var baseRecordConfig = {
                    }; 
										
                    var newRecord = new QFinance.component.MarkEditWindow({
                        ownerWindow: this.getOwnerWindow(),
                        record: new this.record(baseRecordConfig),
                        listeners: {
                            scope: this,
                            save: function( record ) {
                                this.store.add( record );
                                this.doSave();								
                            }
                        }
                    });
                    newRecord.show();
                }
            });
        }
		
        if (this.canEdit) {
            topBarConfig.push({
                text: this.editText,
                tooltip: this.editTooltipText,
                iconCls: 'fugue-bookmark--pencil',
                scope: this,
                handler: function() {
                    var selectedRecord = this.grid.getSelectionModel().getSelected();
					
                    if (selectedRecord) {
                        var editRecord = new QFinance.component.MarkEditWindow({
                            ownerWindow: this.getOwnerWindow(),
                            record: selectedRecord,
                            isNew: false,
                            autoLoadRecord: true,							
                            listeners: {
                                scope: this,
                                save: function(record) {
                                    this.doSave();
                                }
                            }
                        });
                        editRecord.show();
                    } else {
                        var information = new QFinance.ui.MessageBox();
                        information.show({
                            title: this.editInformationTitle,
                            msg: this.editInformationMsg,
                            buttons: Ext.MessageBox.OK,
                            renderTo: this.body,
                            icon: Ext.MessageBox.INFO
                        });
                    }
                }
            });
        }
		
        if (this.canRemove) {
            topBarConfig.push({
                text: this.removeText,
                tooltip: this.removeTooltipText,
                iconCls: 'fugue-bookmark--minus',
                scope: this,
                handler: function() {
                    var selectedRecords = this.grid.getSelectionModel().getSelections();
					
                    if (selectedRecords.length > 0) {
                        var question = new QFinance.ui.MessageBox();
                        question.show({
                            title: this.removeQuestionTitle,
                            msg: this.removeQuestionMsg,
                            buttons: Ext.MessageBox.YESNO,
                            scope: this,
                            fn: function(btn) {
                                if (btn == 'yes') {
                                    for (var i = 0; i < selectedRecords.length; i++)
                                        this.store.remove( selectedRecords[i] );
                                    this.doSave();
                                }								   
                            },
                            renderTo: this.body,
                            icon: Ext.MessageBox.QUESTION
                        });
                    } else {
                        var information = new QFinance.ui.MessageBox();
                        information.show({
                            title: this.removeInformationTitle,
                            msg: this.removeInformationMsg,
                            buttons: Ext.MessageBox.OK,
                            renderTo: this.body,
                            icon: Ext.MessageBox.INFO
                        });						
                    }
                }
            });
        }
		
        return topBarConfig;
    },
	
    getGridConfig: function(topBar) {
        var gridConfig = {
            store: this.store,			
            columns: [
            {
                id: 'name',
                header: this.markText, 
                sortable: true,
                dataIndex: 'name',
                width: 100
            },{
                id: 'description',
                header: this.descriptionText, 
                sortable: true,
                dataIndex: 'description'
            }],
            stripeRows: true,
            autoExpandColumn: 'description',
            sm: new Ext.grid.RowSelectionModel(),
            tbar: topBar,
            stateful: true,
            stateid: 'QFinance.component.MarksEditPanel.grid'
        };
		
        return gridConfig;
    },
		
    doSave: function() {
        this.store.save();
    },
        
    loadRecords: function() {
        this.store.load();        
    }
});
Ext.reg('QFinance.component.MarksEditPanel', QFinance.component.MarksEditPanel);
/*
 * @depends component.js, Panel.js
 */
QFinance.component.TransactionsEditPanel = Ext.extend( QFinance.ui.Panel, {
    // Configuration
    checkTotalAmount: false,
    canAddTransaction: true,
    canEditTransaction: true,
    canRemoveTransaction: true,
    isSubtransaction: false,
    canViewSubtransactions: true,
    totalAmount: 0,	
    contextAccountID: null,
    contextDate: null,
    temporaryID: null,
    parentTransactionID: null,
    accountEditMode: 'both',
    autoLoadTransactions: false,
    showAccountOverview: false,
    showAccountBalance: false,
    recordDragDrop: false,
    onlyAnnotation: false,
    forceCategorySelection: true,
	
    // Localization
    subtransactionsText: 'Subtransactions',
    addTransactionText: 'Add',
    editTransactionText: 'Edit',
    removeTransactionText: 'Remove',
    recordsTotalText: 'Current amount: {0}',
    totalAmountText: 'Total amount: {0}',
    dateText: 'Date',
    descriptionText: 'Description',
    bankMemoText: 'Bank memo',
    accountText: 'Account',
    amountText: 'Amount',
    categoryText: 'Category',
    markText: 'Mark',
    subtransactionsWindowTitleText: 'Subtransactions of transaction: {0}',
    totalAmountIsntEqualTransactionsAmountText: 'While the total value of transactions is not equal to the parent transaction, the transaction will not be saved.',
    accountOverviewText: 'Account overview',
    accountBalanceText: 'Account balance:',
    removeQuestionTitle: 'Remove transaction',
    removeQuestionMsg: 'Would you like to remove selected transactions?',
    editInformationTitle: 'Edit transaction',
    editInformationMsg: 'Please select an transaction to edit.',
    multiEditInformationTitle: 'Edit multiple transaction',
    multiEditInformationMsg: 'Only accounts of same source/destination can be multi-edited',
    viewSubtransactionsInformationTitle: 'View subtransactions',
    viewSubtransactionsInformationMsg: 'Please select an transaction.',
    removeInformationTitle: 'Remove transaction',
    removeInformationMsg: 'Please select an transaction to remove.',
    saveInformationTitle: 'Save information',
	
    // Components
    store: null,	
    recordsTotalStatusBarItem: null,
    accountBalanceStatusBarItem: null,
    grid: null,
    transactionRecord: null,
    accountOverviewPanel: null,
    saveInfoShowed: false,
	
    constructor: function(config) {
        Ext.apply(this, config);
		
        this.createTransactionRecord();
		
        this.store = new Ext.data.DirectStore({
            autoSave: false,
            autoLoad: false,
            idProperty: 'id',
            root: 'data',
            successProperty: 'success',
            paramsAsHash: false,
            paramOrder: [ 'accountID', 'temporaryID', 'parentTransactionID', 'annotation' ],
            baseParams: {
                accountID: this.contextAccountID, 
                temporaryID: this.temporaryID, 
                parentTransactionID: this.parentTransactionID, 
                annotation: this.onlyAnnotation
            },
            api: {
                read: QFinance.Remoting.TransactionsEditPanelAction.read,
                create: QFinance.Remoting.TransactionsEditPanelAction.create,
                update: QFinance.Remoting.TransactionsEditPanelAction.update,
                destroy: QFinance.Remoting.TransactionsEditPanelAction.destroy
            },
            writer: new Ext.data.JsonWriter({
                encode: false,
                writeAllFields: true
            }),			
            fields: this.transactionRecord,
            listeners: {
                scope: this,
                beforeload: function(store, options) {
                    store.id = this.getProcessStatusManager().start([this]);		
                },				
                load: function(store, records, options) {
                    this.getProcessStatusManager().success(store.id);				
                    this.updateTransactionsAmount();
                    if (this.showAccountBalance) {
                        this.loadAccountBalance();			
                    }
                },
                beforewrite: function(store, action, rs, options, arg ) {
                    store.id = this.getProcessStatusManager().start([this]);
                },
                write: function(store, action, rs, options, arg ) {
                    this.getProcessStatusManager().success(store.id);
                    this.updateTransactionsAmount();
                    if (this.showAccountBalance) {
                        this.loadAccountBalance();			
                    }
                },				
                exception: function(dataProxy, type, action, options, response, arg ) {
                    var message = '';
                    var where = '';
                    if (response.result) {
                        message = response.result.message;
                        if (response.result.type == 'exception')
                            where = response.result.where;
                    } else {
                        message = response.message;
                    }
                    this.getProcessStatusManager().error(this.store.id, message);
                    QFinance.service.DeveloperService.log('Store failure: ' + message + ' where\n' + where);					
                }
            }			
        });
		
        this.addEvents([ 
            'close'
            ]);		
		
        QFinance.component.TransactionsEditPanel.superclass.constructor.call(this);
    },
	
    initComponent: function() {		
        var topBarConfig = this.getTopBarConfig();		
        var topBar = new Ext.Toolbar(topBarConfig);
        var gridConfig = this.getGridConfig(topBar);
        this.grid = new Ext.grid.GridPanel(gridConfig);
		
        //this.initStatusBar();
		
        var items = [this.grid];
        // TODO: Quando der desenvolver e utilizar o 'Account overview'
        /*
		if (this.showAccountOverview)
			items.push(this.accountOverviewPanel = new QFinance.component.AccountOverviewPanel({								
				title: this.accountOverviewText,
				region: 'south',				
				collapsible: true,
				autoHeight: true,
				frame: true
			}));*/		
		
        Ext.apply(this, {
            layout: 'border',
            items: items
        });

        QFinance.component.TransactionsEditPanel.superclass.initComponent.call(this);
    },
	
    createTransactionRecord: function() {
        this.transactionRecord = Ext.data.Record.create([{
            name: 'id',
            type: 'int'
        },{
            name: 'date',		
            type: 'date',	
            dateFormat: "c"
        },{
            name: 'description'
        },{
            name: 'bankMemo'
        },{
            name: 'amount',	
            type: 'float'
        },{
            name: 'sourceAccountID',
            type: 'int',
            useNull: true
        },{
            name: 'sourceAccountName'
        },{
            name: 'destinationAccountID',
            type: 'int',
            useNull: true
        },{
            name: 'destinationAccountName'
        },{
            name: 'categoryID', 
            type: 'int',
            useNull: true
        },{
            name: 'categoryName'
        },{
            name: 'hasSubtransactions',
            type: 'bolean'
        },{
            name: 'subtransactions',
            type: 'auto'
        },{
            name: 'financialNumber'
        },{
            name: 'temporaryID',
            type: 'int',
            useNull: true
        },{
            name: 'parentTransactionID',
            type: 'int',
            useNull: true
        },{
            name: 'annotation',
            type: 'bolean'
        },{
            name: 'markID',
            type: 'int',
            useNull: true
        },{
            name: 'markName'
        }]);
    },
	
    getTopBarConfig: function() {
        var topBarConfig = [];
		
        if (this.canViewSubtransactions) {
            topBarConfig.push({
                text: this.subtransactionsText,
                iconCls: 'fugue-moneys',
                scope: this,
                handler: function() {	
                    var selectedRecord = this.grid.getSelectionModel().getSelected();
					
                    if (selectedRecord) {
                        var accountEditMode = QFinance.component.TransactionEditWindow.editModes.BOTH;
                        if (selectedRecord.get('sourceAccountID') == this.contextAccountID)
                            accountEditMode = QFinance.component.TransactionEditWindow.editModes.DESTINATION;
                        else if (selectedRecord.get('destinationAccountID') == this.contextAccountID)
                            accountEditMode = QFinance.component.TransactionEditWindow.editModes.SOURCE;							
						
                        var subtransactionsWindow = new QFinance.component.TransactionsEditWindow({
                            width: this.body.dom.offsetWidth - 20,
                            height: this.body.dom.offsetHeight - 20,
                            ownerWindow: this.getOwnerWindow(),
                            title: String.format(this.subtransactionsWindowTitleText, selectedRecord.get('description')),
                            transactionsEditPanelConfig: {
                                checkTotalAmount: true,
                                canAddTransaction: true,
                                canEditTransaction: true,
                                canRemoveTransaction: true,
                                isSubtransaction: true,
                                canViewSubtransactions: true,
                                totalAmount: selectedRecord.get('amount'),									
                                contextAccountID: this.contextAccountID,
                                contextDate: selectedRecord.get('date'),
                                temporaryID: this.temporaryID,							
                                parentTransactionID: selectedRecord.get('id'),
                                accountEditMode: accountEditMode,
                                autoLoadTransactions: true								
                            },
                            listeners: {
                                scope: this,
                                close: function() {
                                    this.updateIfHasSubtransactions( selectedRecord );
                                }
                            }
                        });
                        subtransactionsWindow.show();
                    } else {
                        var information = new QFinance.ui.MessageBox();
                        information.show({
                            title: this.viewSubtransactionsInformationTitle,
                            msg: this.viewSubtransactionsInformationMsg,
                            buttons: Ext.MessageBox.OK,
                            renderTo: this.body,
                            icon: Ext.MessageBox.INFO
                        });
                    }
                }
            });
        }
		
        if (this.canAddTransaction) {
            topBarConfig.push({
                text: this.addTransactionText,
                iconCls: 'fugue-money--plus',
                scope: this,
                handler: function() {
                    var baseRecordConfig = {
                        temporaryID: this.temporaryID,
                        parentTransactionID: this.parentTransactionID,
                        annotation: this.onlyAnnotation
                    }; 
                    var canChangeDate;
                    var canChangeAmount = true;
                    var contextAccountID = this.contextAccountID;
                    var accountEditMode;
					
                    if (this.isSubtransaction) {
                        canChangeDate = false;
                        accountEditMode = this.accountEditMode;						
                        baseRecordConfig.date = this.contextDate;						
                        if (this.accountEditMode == QFinance.component.TransactionEditWindow.editModes.SOURCE)
                            baseRecordConfig.destinationAccountID = this.contextAccountID;
                        else if (this.accountEditMode == QFinance.component.TransactionEditWindow.editModes.DESTINATION)
                            baseRecordConfig.sourceAccountID = this.contextAccountID;

                    } else {
                        canChangeDate = true;
                        contextAccountID = null;
                        accountEditMode = QFinance.component.TransactionEditWindow.editModes.BOTH;						
                    }
					
                    var newTransaction = new QFinance.component.TransactionEditWindow({
                        ownerWindow: this.getOwnerWindow(),
                        record: new this.transactionRecord(baseRecordConfig),
                        accountEditMode: accountEditMode,
                        contextAccountID: contextAccountID,
                        canChangeDate: canChangeDate,
                        canChangeAmount: canChangeAmount,
                        requireCategory: this.forceCategorySelection,
                        listeners: {
                            scope: this,
                            save: function( record ) {
                                this.store.add( record );
                                this.doSave();								
                            }
                        }
                    });
                    newTransaction.show();
                }
            });
        }
		
        if (this.canEditTransaction) {
            topBarConfig.push({
                text: this.editTransactionText,
                iconCls: 'fugue-money--pencil',
                scope: this,
                handler: function() {
                    var selectedRecords = this.grid.getSelectionModel().getSelections();
                    var accountEditMode;
                    var canChangeCategory;
                    var contextAccountID;
                    var editTransactionWindow;
                    var informationMessageBox;
					
                    if (selectedRecords.length == 1) {
                        var selectedRecord = selectedRecords[0];
                        var canChangeAmount;
                        var canChangeDate;
						
                        if (this.isSubtransaction) {
                            canChangeAmount = true;
                            canChangeCategory = true;
                            canChangeDate = false;
                            contextAccountID = this.contextAccountID;
							
                            if (selectedRecord.get('sourceAccountID') == this.contextAccountID)
                                accountEditMode = QFinance.component.TransactionEditWindow.editModes.DESTINATION;
                            else if (selectedRecord.get('destinationAccountID') == this.contextAccountID)
                                accountEditMode = QFinance.component.TransactionEditWindow.editModes.SOURCE;							
                        } else {
                            canChangeAmount = !selectedRecord.get('hasSubtransactions');
                            canChangeCategory = !selectedRecord.get('hasSubtransactions');
                            canChangeDate = !selectedRecord.get('hasSubtransactions');
                            contextAccountID = null;
							
                            if (selectedRecord.get('hasSubtransactions')) {
                                if (selectedRecord.get('sourceAccountID') == this.contextAccountID)
                                    accountEditMode = QFinance.component.TransactionEditWindow.editModes.DESTINATION;
                                else if (selectedRecord.get('destinationAccountID') == this.contextAccountID)
                                    accountEditMode = QFinance.component.TransactionEditWindow.editModes.SOURCE;								
                            } else {
                                accountEditMode = QFinance.component.TransactionEditWindow.editModes.BOTH;	
                            }														
                        }
                        editTransactionWindow = new QFinance.component.TransactionEditWindow({
                            ownerWindow: this.getOwnerWindow(),
                            record: selectedRecord,
                            isNew: false,
                            autoLoadRecord: true,
                            contextAccountID: contextAccountID,
                            accountEditMode: accountEditMode,
                            canChangeAmount: canChangeAmount,
                            canChangeCategory: canChangeCategory,
                            canChangeDate: canChangeDate,														
                            requireCategory: selectedRecord.get('hasSubtransactions') ? false : this.forceCategorySelection,
                            listeners: {
                                scope: this,
                                save: function(record) {
                                    this.doSave();
                                }
                            }
                        });
                        editTransactionWindow.show();
                    } else if (selectedRecords.length > 0) {
                        // Check if selected records is of same direction (income, expense)
                        var sameSourceAccountID = true;
                        var sameDestinationAccountID = true;
                        var sourceAccountID = selectedRecords[0].get('sourceAccountID');
                        var destinationAccountID = selectedRecords[0].get('destinationAccountID');
                        Ext.each(selectedRecords, function(record) {
                            if (record.get('sourceAccountID') != sourceAccountID)
                                sameSourceAccountID = false;
                            if (record.get('destinationAccountID') != destinationAccountID)
                                sameDestinationAccountID = false;
                        });
                    
                        if (!sameSourceAccountID && !sameDestinationAccountID) {
                            informationMessageBox = new QFinance.ui.MessageBox();
                            informationMessageBox.show({
                                title: this.multiEditInformationTitle,
                                msg: this.multiEditInformationMsg,
                                buttons: Ext.MessageBox.OK,
                                renderTo: this.body,
                                icon: Ext.MessageBox.INFO
                            });
                            return
                        }                            
                        
                        // Determine transaction edit mode
                        
                        if (sourceAccountID != null && sameSourceAccountID)
                            accountEditMode = QFinance.component.TransactionEditWindow.editModes.DESTINATION;
                        else if (destinationAccountID != null && sameDestinationAccountID)
                            accountEditMode = QFinance.component.TransactionEditWindow.editModes.SOURCE;
                        
                        // Determine if can change category
                        canChangeCategory = true;
                        Ext.each(selectedRecords, function(record) {
                            if (record.get('hasSubtransactions')) 
                                canChangeCategory = false;                               
                        });
                        
                        contextAccountID = this.contextAccountID;
                        
                        editTransactionWindow = new QFinance.component.TransactionMultiEditWindow({
                            ownerWindow: this.getOwnerWindow(),
                            records: selectedRecords,                            
                            contextAccountID: contextAccountID,
                            accountEditMode: accountEditMode,                            
                            canChangeCategory: canChangeCategory,
                            canChangeDate: canChangeDate,														
                            requireCategory: canChangeCategory,
                            listeners: {
                                scope: this,
                                save: function(record) {
                                    this.doSave();
                                }
                            }
                        });
                        editTransactionWindow.show();
                    } else {
                        informationMessageBox = new QFinance.ui.MessageBox();
                        informationMessageBox.show({
                            title: this.editInformationTitle,
                            msg: this.editInformationMsg,
                            buttons: Ext.MessageBox.OK,
                            renderTo: this.body,
                            icon: Ext.MessageBox.INFO
                        });
                    }
                }
            });
        }
		
        if (this.canRemoveTransaction) {
            topBarConfig.push({
                text: this.removeTransactionText,
                iconCls: 'fugue-money--minus',
                scope: this,
                handler: function() {
                    var selectedRecords = this.grid.getSelectionModel().getSelections();
					
                    if (selectedRecords.length > 0) {
                        var question = new QFinance.ui.MessageBox();
                        question.show({
                            title: this.removeQuestionTitle,
                            msg: this.removeQuestionMsg,
                            buttons: question.YESNO,
                            icon: question.QUESTION,
                            scope: this,
                            fn: function(btn) {
                                if (btn == 'yes') {
                                    Ext.each(selectedRecords, function(record) {
                                        this.store.remove( record );
                                    });
                                    this.doSave();
                                }								   
                            },
                            renderTo: this.body					   
                        });
                    } else {
                        var information = new QFinance.ui.MessageBox();
                        information.show({
                            title: this.removeInformationTitle,
                            msg: this.removeInformationMsg,
                            buttons: Ext.MessageBox.OK,
                            renderTo: this.body,
                            icon: Ext.MessageBox.INFO
                        });						
                    }
                }
            });
        }
		
        return topBarConfig;
    },
	
    initStatusBar: function( toolbar ) {
        if (this.checkTotalAmount) {
            this.recordsTotalStatusBarItem = new Ext.Toolbar.TextItem({
                text: '?'
            });
            toolbar.insert(0, '-');
            toolbar.insert(0, new Ext.Toolbar.TextItem({ 
                text: String.format(this.totalAmountText,QFinance.moneySymbol + ' ' + Ext.util.Format.number(this.totalAmount,QFinance.numberFormat)) 
            }));            
            toolbar.insert(0, this.recordsTotalStatusBarItem);
        }

        if (this.showAccountBalance){
            this.accountBalanceStatusBarItem = new Ext.Toolbar.TextItem({
                text: '?'
            });

            toolbar.insert(0, this.accountBalanceStatusBarItem);
            toolbar.insert(0, this.accountBalanceText);			
        }
    },
	
    getGridConfig: function(topBar) {
        var gridConfig = {
            region: 'center',
            store: this.store,	
            ddGroup: 'gridDDGroup',
            enableDragDrop: this.recordDragDrop,
            columns: [
            {
                id       :'date',
                header   : this.dateText, 
                sortable : true, 
                dataIndex: 'date',
                renderer: Ext.util.Format.dateRenderer(QFinance.dateFormat),
                editor: {
                    xtype: 'textfield',
                    allowBlank: false
                },
                width: 80
            },{
                id       :'description',
                header   : this.descriptionText, 
                sortable : true, 
                dataIndex: 'description'
            },{
                id       :'bankMemo',
                header   : this.bankMemoText, 
                sortable : true, 
                dataIndex: 'bankMemo'
            },{
                id	: 'accountName',
                header	: this.accountText,
                sortable: true,
                scope: this,
                renderer: function(value, metaData, record, rowIndex, colIndex, store) {
                    var renderedText = '';
                    if (this.contextAccountID) {
                        if (this.contextAccountID == record.get('sourceAccountID')) {
                            renderedText = record.get('destinationAccountName');
                        } else if (this.contextAccountID == record.get('destinationAccountID')) {
                            renderedText = record.get('sourceAccountName');
                        }
                    }
                    return renderedText;
                }
            },{
                id       :'amount',
                header   : this.amountText, 
                sortable : true, 
                dataIndex: 'amount',
                scope: this,
                renderer: function(value, metaData, record, rowIndex, colIndex, store) {
                    var renderedText = '';
                    if (this.contextAccountID) {
                        if (this.contextAccountID == record.get('sourceAccountID')) {
                            renderedText = '<span style="color:red;">' + QFinance.moneySymbol + ' ' + Ext.util.Format.number(value,QFinance.numberFormat) + '</span>';
                        } else if (this.contextAccountID == record.get('destinationAccountID')) {
                            renderedText = '<span style="color:green;">' + QFinance.moneySymbol + ' ' + Ext.util.Format.number(value,QFinance.numberFormat) + '</span>';
                        }
                    } else {
                        renderedText = QFinance.moneySymbol + ' ' + Ext.util.Format.number(value,QFinance.numberFormat);
                    }
                    return renderedText;
                }
            },{
                id		: 'categoryName',
                header		: this.categoryText, 
                sortable	: true, 
                dataIndex	: 'categoryName'
            },{
                id		: 'markName',
                header		: this.markText, 
                sortable	: true, 
                dataIndex	: 'markName'
            },{
                id		: 'hasSubtransactions',
                header		: '',
                sortable	: true,
                width		: 16,
                dataIndex	: 'hasSubtransactions',
                renderer: function(value, metaData, record, rowIndex, colIndex, store) {
                    if (value) {
                        metaData.css = 'fugue-moneys-cell';	        			
                    }
                }	        		
            }],
            stripeRows: true,
            autoExpandColumn: 'description',
            sm: new Ext.grid.RowSelectionModel(),
            tbar: topBar	        
        };
		
        return gridConfig;
    },
	
    updateIfHasSubtransactions: function( selectedRecord ) {
        var updateProcessID = this.getProcessStatusManager().start([this]);
        this.disable();
        QFinance.Remoting.TransactionsEditPanelAction.hasSubtransactions(selectedRecord.get('id'), function(result, event) {
            var message = '';
            var where = '';
            var failure = false;
			
            if (result) {
                if (result.success) {
                    this.getProcessStatusManager().success(updateProcessID);                    
                    selectedRecord.set('hasSubtransactions', result.hasSubtransactions);
                    selectedRecord.set('categoryID', null);
                    selectedRecord.set('categoryName', null);
                    this.doSave();		
                } else {
                    failure = true;						
                    message = result.message;
                    if (result.type == 'exception')
                        where = result.where;
                }            
            } else {
                failure = true;
                message = event.message;
            }
			
            if (failure) {
                this.getProcessStatusManager().error(updateProcessID, message);                
                QFinance.service.DeveloperService.log('Direct call failure: ' + message + ' where\n' + where);
            }
			
            this.enable();			
        }, this);
    },
	
    getTransactionsAmount: function() {
        var recordsSum = 0;
        this.store.each(function(record) {
            recordsSum += record.get('amount');
        });
        return recordsSum.toFixed(2);
    },
	
    updateTransactionsAmount: function() {
        if (this.checkTotalAmount) {			
            var recordsSum = this.getTransactionsAmount();
			
            this.recordsTotalStatusBarItem.setText(String.format(this.recordsTotalText, QFinance.moneySymbol + ' ' + Ext.util.Format.number(recordsSum,QFinance.numberFormat)));
        }
    },
	
    doSave: function() {		
        if (this.checkTotalAmount) {
            var transactionsAmount = this.getTransactionsAmount(); 
            if (transactionsAmount == 0 || transactionsAmount == this.totalAmount) {
                this.store.save();
                this.updateTransactionsAmount();
            } else {
                this.updateTransactionsAmount();
                if (!this.saveInfoShowed) {
                    this.getOwnerWindow().showInfoMessageBox(this.saveInformationTitle, this.totalAmountIsntEqualTransactionsAmountText);
                    this.saveInfoShowed = true;
                }                
            }
        } else {
            this.store.save();
            this.updateTransactionsAmount();
        }
    },
	
    setContextAccountID: function( id ) {
        this.contextAccountID = id;
        this.store.setBaseParam('accountID', id);
    },
	
    setTemporaryTransactionID: function( id ) {
        this.temporaryID = id;
        this.store.setBaseParam('temporaryID', id);
        this.store.reload();
    },
	
    load: function() {
        this.store.setBaseParam('accountID', this.contextAccountID);
        this.store.setBaseParam('temporaryID', this.temporaryID);
        this.store.setBaseParam('parentTransactionID', this.parentTransactionID);		
        this.store.load();		
    // TODO: A mesma coisa do \todo anterior
    /*
        if (this.showAccountOverview)
                this.accountOverviewPanel.load( this.contextAccountID );*/
    },
	
    loadAccountBalance: function() {
        if (this.contextAccountID) {
            var loadAccountBalanceID = this.getProcessStatusManager().start([this]);            
            QFinance.Remoting.TransactionsEditPanelAction.getAccountBalance(this.contextAccountID, function(result, event) {
                var message = '';
                var where = '';
                var failure = false;
				
                if (result) {
                    if (result.success) {
                        this.getProcessStatusManager().success(loadAccountBalanceID);
                        this.accountBalanceStatusBarItem.removeClass('qfinance-red');
                        this.accountBalanceStatusBarItem.removeClass('qfinance-blue');
                        if (result.accountBalance >= 0) {
                            this.accountBalanceStatusBarItem.addClass('qfinance-blue');
                            this.accountBalanceStatusBarItem.setText(QFinance.moneySymbol + ' ' + Ext.util.Format.number(result.accountBalance,QFinance.numberFormat));
                        } else {
                            this.accountBalanceStatusBarItem.addClass('qfinance-red');
                            this.accountBalanceStatusBarItem.setText(QFinance.moneySymbol + ' ' + Ext.util.Format.number(result.accountBalance *= -1,QFinance.numberFormat));		    		
                        } 
                    } else {
                        failure = true;						
                        message = result.message;
                        if (result.type == 'exception')
                            where = result.where;
                    }            
                } else {
                    failure = true;
                    message = event.message;
                }
				
                if (failure) {
                    this.getProcessStatusManager().error(loadAccountBalanceID, message);					
                    QFinance.service.DeveloperService.log('Direct call failure: ' + message + ' where\n' + where);
                }               		
            }, this);	
        }
    },
	
	
    render: function(ct, position) {
        QFinance.component.TransactionsEditPanel.superclass.render.call(this, ct, position);
		
        if (this.autoLoadTransactions)
            this.load();	
    }
});
Ext.reg('transactionseditpanel', QFinance.component.TransactionsEditPanel);
/*
 * @depends component.js, Panel.js
 */
QFinance.component.TransactionsImportPanel = Ext.extend( QFinance.ui.Panel, {
    // Localization
    welcomeText: 'Welcome, bla bla bla',
    bankText: 'Bank',
    bankEmptyText: 'Select a bank...',
    fileText: 'File',
    fileEmptyText: 'Select a file',
    accountText: 'Account',
    accountEmptyText: 'Select an account',
    finishButtonText: 'Finish', 
    finishText: '{0} transactions are ready to be imported into the {1}, click \'{2}\' to make them permanent.',    
	
    // State
    imported: false,
	
    // Components
    wizard: null,	
    formPanel: null,
    transactionsEditPanel: null,
    accountStore: null,
	
    constructor: function(config) {
        Ext.apply(this, config);
		
        this.addEvents(['importData']);		
		
        QFinance.component.TransactionsImportPanel.superclass.constructor.call(this);
    },
	
    initComponent: function() {
        this.wizard = this.getWizardItem();
				
        Ext.apply(this, {
            layout: 'fit',			
            items: [ this.wizard ]
        });
		
        QFinance.component.TransactionsImportPanel.superclass.initComponent.call(this);
    },
	
    getWizardItem: function() {
        var wizardItem = new QFinance.ui.WizardPanel({            
            listeners: {
                scope: this,
                beforeitemchange: function( wizard, fromItem, toItem ) {
                    var canChange = true;
                    if (fromItem.itemName == 'Parameters' && toItem.itemName == 'Transactions') {
                        if (this.formPanel.getForm().isValid())
                            canChange = true;
                        else							
                            canChange = false;
                    }
                    return canChange;
                },
                itemchange: function( wizard, fromItem, toItem ) {
                    if (fromItem.itemName == 'Parameters' && toItem.itemName == 'Transactions') {
                        var sendFileID = this.getProcessStatusManager().start([this.transactionEditPanel]);
                        this.checkTemporaryTransactionsGhosts(function() {
                            this.formPanel.getForm().submit({
                                scope: this,
                                success: function(form, action) {
                                    this.getProcessStatusManager().success(sendFileID);
                                    this.imported = false;
                                    this.transactionsEditPanel.setContextAccountID(parseInt(this.formPanel.getForm().findField('accountID').getValue()));
                                    this.transactionsEditPanel.setTemporaryTransactionID(action.result.temporaryID);				
                                },
                                failure: function(form, action) {
                                    var message = '';
                                    var where = '';
                                    switch (action.failureType) {			
                                        case Ext.form.Action.CLIENT_INVALID:
                                            message = 'Form fields may not be submitted with invalid values';			    
                                            break;
                                        case Ext.form.Action.CONNECT_FAILURE:
                                            message = 'Ajax communication failed';
                                            break;
                                        case Ext.form.Action.SERVER_INVALID:
                                            message = action.result.message;
                                            if (action.result.type == 'exception')
                                                where = action.result.where;
                                            break;
                                    }
                                    this.getProcessStatusManager().error(sendFileID, message);
                                    QFinance.service.DeveloperService.log('Submit failure: ' + message + ' where\n' + where);
                                }								
                            });	
                        }, this);
                    } else if (fromItem.itemName == 'Transactions' && toItem.itemName == 'Finish') {
                        toItem.items.get(0).el.dom.innerText = String.format(this.finishText, this.transactionsEditPanel.store.getTotalCount(), this.formPanel.getForm().findField('accountID').getRawValue(), this.finishButtonText);
                    }					
                },
                finish: function( wizard ) {
                    this.doImportData();
                }
            }
        });
		
        wizardItem.items.add(new Ext.Panel({
            itemName: 'Parameters',
            layout: {
                type: 'vbox',
                pack: 'start',
                align: 'stretch',
                defaultMargins: '10'
            },            	    
            defaults: {
                frame: false,  
                border: false
            },
            items: [{
                flex: 1,
                autoScroll: true,
                html: this.welcomeText
            },{       
                flex: 1,
                layout: {
                    type: 'vbox',
                    pack: 'start',
                    align: 'center',
                    defaultMargins: '10'
                },      
                defaults: {
                    frame: false,  
                    border: false
                },
                items: [ this.formPanel = new Ext.form.FormPanel({
                    width: 300,
                    fileUpload: true,
                    labelWidth: 50,
                    defaults: {
                        anchor: '100%',
                        allowBlank: false
                    },                	    	
                    items: [{
                        xtype: 'combo',
                        fieldLabel: this.bankText,
                        typeAhead: true,
                        triggerAction: 'all',
                        emptyText: this.bankEmptyText,
                        selectOnFocus: true,
                        forceSelection: true,
                        store: [
                        ['1', 'Banco Real'],
                        ['2', 'Banco Itaú'],
                        ['3', 'Caixa']
                        ],
                        hiddenName: 'bankID',
                        name: 'bank'
                    },{
                        xtype: 'combo',
                        fieldLabel: this.accountText,	    				
                        store: this.accountStore = new Ext.data.DirectStore({
                            directFn: QFinance.Remoting.AccountAction.getByAccountType,
                            paramsAsHash: false,
                            autoLoad: true,
                            paramOrder: [ 'type' ],
                            baseParams: {
                                type: '1'
                            },
                            idProperty: 'id',
                            root: 'data',
                            successProperty: 'success',
                            fields: [
                            {
                                name: 'id',
                                type: 'int'
                            },
                            {
                                name: 'accountName'	    		    
                            },
                            {
                                name: 'accountType'
                            }
                            ],
                            listeners: {
                                scope: this,
                                beforeload: function(store, options) {
                                    store.id = this.getProcessStatusManager().start([this]);
                                },				
                                load: function(store, records, options) {
                                    this.getProcessStatusManager().success(store.id);
                                },
                                exception: function(dataProxy, type, action, options, response, arg ) {
                                    var message = '';
                                    var where = '';
                                    if (response.result) {
                                        message = response.result.message;
                                        if (response.result.type == 'exception')
                                            where = response.result.where;
                                    } else {
                                        message = response.message;
                                    }
                                    this.getProcessStatusManager().error(this.accountStore.id, message);                                    
                                    QFinance.service.DeveloperService.log('Store failure: ' + message + ' where\n' + where);
                                }
                            }						
                        }),
                        typeAhead: true,
                        triggerAction: 'all',
                        emptyText: this.accountEmptyText,
                        selectOnFocus: true,
                        valueField: 'id',
                        displayField: 'accountName',
                        hiddenName: 'accountID',
                        forceSelection: true,
                        mode: 'local',	    	        	
                        name: 'account'
                    },{
                        xtype: 'fileuploadfield',
                        emptyText: this.fileEmptyText,
                        fieldLabel: this.fileText,
                        buttonText: '',
                        buttonCfg: {
                            iconCls: 'fugue-document--plus'
                        },
                        name: 'file'
                    }],
                    api: {
                        submit: QFinance.Remoting.TransactionsImportPanelAction.importData	            		
                    }	
                })]
            }]
        }));
		
        wizardItem.items.add(new Ext.Panel({
            itemName: 'Transactions',
            layout: 'fit',
            items: [ this.transactionsEditPanel = new QFinance.component.TransactionsEditPanel() ]
        }));
		
        wizardItem.items.add(new Ext.Panel({
            itemName: 'Finish',
            layout: {
                type: 'vbox',
                pack: 'start',
                align: 'stretch',
                defaultMargins: '10'
            },            	    
            defaults: {
                frame: false,  
                border: false
            },
            items: [{
                flex: 1,
                autoScroll: true,
                html: this.finishText
            }] 
        }));
		
        return wizardItem;
    },
	
    doImportData: function() {
        var importDataID = this.getProcessStatusManager().start([this]);        
        QFinance.Remoting.TransactionsImportPanelAction.makePermanent(this.transactionsEditPanel.temporaryID, function(result, event) {
            var message = '';
            var where = '';
            var failure = false;
			
            if (result) {
                if (result.success) {
                    this.getProcessStatusManager().success(importDataID);
                    this.imported = true;
                    this.fireEvent('importData');		
                } else {
                    failure = true;						
                    message = result.message;
                    if (result.type == 'exception')
                        where = result.where;
                }            
            } else {
                failure = true;
                message = event.message;
            }
			
            if (failure) {
                this.getProcessStatusManager().error(importDataID, message);
                QFinance.service.DeveloperService.log('Direct call failure: ' + message + ' where\n' + where);
            }           		
        }, this);		
    },
	
    checkTemporaryTransactionsGhosts: function(callback, scope) {
        if (this.transactionsEditPanel.temporaryID && !this.imported) {
            var temporaryTransactionsGhostsID = this.getProcessStatusManager().start([this]);
            QFinance.Remoting.TransactionsImportPanelAction.removeTemporaryTransactions(this.transactionsEditPanel.temporaryID, function(result, event) {
                var message = '';
                var where = '';
                var failure = false;
				
                if (result) {
                    if (result.success) {
                        this.getProcessStatusManager().success(temporaryTransactionsGhostsID);                        
                        if (callback) callback.call(scope||this);		
                    } else {
                        failure = true;						
                        message = result.message;
                        if (result.type == 'exception')
                            where = result.where;
                    }            
                } else {
                    failure = true;
                    message = event.message;
                }
				
                if (failure) {
                    this.getProcessStatusManager().error(temporaryTransactionsGhostsID, message);
                    QFinance.service.DeveloperService.log('Direct call failure: ' + message + ' where\n' + where);
                }
            }, this);			
        } else {
            if (callback) callback.call(scope||this);
        }
    }
});
Ext.reg('QFinance.component.TransactionsImportPanel', QFinance.component.TransactionsImportPanel);
/*
 * @depends component.js, Panel.js
 */
QFinance.component.UsersEditPanel = Ext.extend( QFinance.ui.Panel, {
    // Configuration
    autoLoadUsers: true,
    canAddUser: true,
    canEditUser: true,
    canRemoveUser: true,
	
    // Localization	
    addUserText: 'Add',
    addUserTooltipText: 'Add a new user',
    editUserText: 'Edit',
    editUserTooltipText: 'Edit user',
    removeUserText: 'Remove',
    removeUserTooltipText: 'Remove user',
    userText: 'User',    
    removeQuestionTitle: 'Remove user',
    removeQuestionMsg: 'Would you like to remove selected users?',
    editInformationTitle: 'Edit user',
    editInformationMsg: 'Please select a user to edit.',
    removeInformationTitle: 'Remove user',
    removeInformationMsg: 'Please select a user to remove.',	
	
    // Components
    store: null,		
    grid: null,
    userRecord: null,	
	
    constructor: function(config) {
        Ext.apply(this, config);
		
        this.createUserRecord();
		
        this.store = new Ext.data.DirectStore({
            autoSave: false,
            autoLoad: false,
            idProperty: 'id',
            root: 'data',
            successProperty: 'success',
            paramsAsHash: false,    		
            api: {
                read: QFinance.Remoting.UsersEditPanelAction.read,
                create: QFinance.Remoting.UsersEditPanelAction.create,
                update: QFinance.Remoting.UsersEditPanelAction.update,
                destroy: QFinance.Remoting.UsersEditPanelAction.destroy
            },
            writer: new Ext.data.JsonWriter({
                encode: false,
                writeAllFields: true
            }),			
            fields: this.userRecord,
            listeners: {
                scope: this,
                beforeload: function(store, options) {
                    store.id = this.getProcessStatusManager().start([this]);
                },				
                load: function(store, records, options) {
                    this.getProcessStatusManager().success(store.id);
                },
                beforewrite: function(  store, action, rs, options, arg ) {
                    store.id = this.getProcessStatusManager().start([this]);                    
                },
                write: function(  store, action, rs, options, arg ) {
                    this.getProcessStatusManager().success(store.id);
                },				
                exception: function(dataProxy, type, action, options, response, arg ) {
                    var message = '';
                    var where = '';
                    if (response.result) {
                        message = response.result.message;
                        if (response.result.type == 'exception')
                            where = response.result.where;
                    } else {
                        message = response.message;
                    }
                    this.getProcessStatusManager().error(this.store.id, message);
                    QFinance.service.DeveloperService.log('Store failure: ' + message + ' where\n' + where);					
                }
            }
        });
		
        this.addEvents([ 
            'close'
            ]);		
		
        QFinance.component.UsersEditPanel.superclass.constructor.call(this);
    },
	
    initComponent: function() {		
        var topBarConfig = this.getTopBarConfig();		
        var topBar = new Ext.Toolbar(topBarConfig);
        var gridConfig = this.getGridConfig(topBar);
        this.grid = new Ext.grid.GridPanel(gridConfig);
				
        Ext.apply(this,{
            layout: 'fit',			
            items: [this.grid]
        });

        if (this.autoLoadUsers)
            this.load();

        QFinance.component.UsersEditPanel.superclass.initComponent.call(this);
    },
	
    createUserRecord: function() {
        this.userRecord = Ext.data.Record.create([{
            name: 'id',
            type: 'int'
        },{
            name: 'username'
        },{
            name: 'newPassword'
        }]);
    },
	
    getTopBarConfig: function() {
        var topBarConfig = [];
				
        if (this.canAddUser) {
            topBarConfig.push({
                text: this.addUserText,
                tooltip: this.addUserTooltipText,
                iconCls: 'fugue-user--plus',
                scope: this,
                handler: function() {
                    var baseRecordConfig = {
                    }; 
										
                    var newUser = new QFinance.component.UserEditWindow({
                        renderTo: this.getEl(),
                        constrain: true,
                        modal: true,
                        record: new this.userRecord(baseRecordConfig),
                        listeners: {
                            scope: this,
                            save: function( record ) {
                                this.store.add( record );
                                this.doSave();								
                            }
                        }
                    });
                    newUser.show();
                }
            });
        }
		
        if (this.canEditUser) {
            topBarConfig.push({
                text: this.editUserText,
                tooltip: this.editUserTooltipText,
                iconCls: 'fugue-user--pencil',
                scope: this,
                handler: function() {
                    var selectedRecord = this.grid.getSelectionModel().getSelected();
					
                    if (selectedRecord) {
                        var editUser = new QFinance.component.UserEditWindow({
                            renderTo: this.getEl(),
                            constrain: true,
                            modal: true,
                            record: selectedRecord,
                            isNew: false,
                            autoLoadRecord: true,							
                            listeners: {
                                scope: this,
                                save: function(record) {
                                    this.doSave();
                                }
                            }
                        });
                        editUser.show();
                    } else {
                        var information = new QFinance.ui.MessageBox();
                        information.show({
                            title: this.editInformationTitle,
                            msg: this.editInformationMsg,
                            buttons: Ext.MessageBox.OK,
                            renderTo: this.body,
                            icon: Ext.MessageBox.INFO
                        });
                    }
                }
            });
        }
		
        if (this.canRemoveUser) {
            topBarConfig.push({
                text: this.removeUserText,
                tooltip: this.removeUserTooltipText,
                iconCls: 'fugue-user--minus',
                scope: this,
                handler: function() {
                    var selectedRecords = this.grid.getSelectionModel().getSelections();
					
                    if (selectedRecords.length > 0) {
                        var question = new QFinance.ui.MessageBox();
                        question.show({
                            title: this.removeQuestionTitle,
                            msg: this.removeQuestionMsg,
                            buttons: Ext.MessageBox.YESNO,
                            scope: this,
                            fn: function(btn) {
                                if (btn == 'yes') {
                                    for (i = 0; i < selectedRecords.length; i++)
                                        this.store.remove( selectedRecords[i] );
                                    this.doSave();
                                }								   
                            },
                            renderTo: this.body,
                            icon: Ext.MessageBox.QUESTION
                        });
                    } else {
                        var information = new QFinance.ui.MessageBox();
                        information.show({
                            title: this.removeInformationTitle,
                            msg: this.removeInformationMsg,
                            buttons: Ext.MessageBox.OK,
                            renderTo: this.body,
                            icon: Ext.MessageBox.INFO
                        });						
                    }
                }
            });
        }
		
        return topBarConfig;
    },
	
    getGridConfig: function(topBar) {
        var gridConfig = {
            store: this.store,			
            columns: [
            {
                id		: 'username',
                header		: this.userText, 
                sortable	: true,
                dataIndex	: 'username'	            
            }],
            stripeRows: true,
            autoExpandColumn: 'username',
            sm: new Ext.grid.RowSelectionModel(),
            tbar: topBar,
            stateful: true,
            stateid: 'QFinance.component.UsersEditPanel.grid'
        };
		
        return gridConfig;
    },
		
    doSave: function() {
        this.store.save();
    },
	
    load: function() {
        this.store.load();
    }
});
Ext.reg('QFinance.component.UsersEditPanel', QFinance.component.UsersEditPanel);
/*
 * @depends ui.js
 */
QFinance.ui.MessageBox = function(){
    this.bufferIcon = '';
    this.iconCls = '';
    this.buttonNames = ['ok', 'yes', 'no', 'cancel'];

    // private
    this.handleButton = function(button){
        this.buttons[button].blur();
        if(this.dlg.isVisible()){
            this.dlg.hide();
            this.handleHide();
            Ext.callback(this.opt.fn, this.opt.scope||window, [button, this.activeTextEl.dom.value, this.opt], 1);
        }
    };

    // private
    this.handleHide = function(){
        if(this.opt && this.opt.cls){
            this.dlg.el.removeClass(this.opt.cls);
        }
        this.progressBar.reset();        
    };

    // private
    this.handleEsc = function(d, k, e){
        if(this.opt && this.opt.closable !== false){
            this.dlg.hide();
            this.handleHide();
        }
        if(e){
            e.stopEvent();
        }
    };

    // private
    this.updateButtons = function(b){
        var width = 0,
        cfg;
        if(!b){
            Ext.each(this.buttonNames, function(name){
                this.buttons[name].hide();
            }, this);
            return width;
        }
        this.dlg.footer.dom.style.display = '';
        Ext.iterate(this.buttons, function(name, btn){
            cfg = b[name];
            if(cfg){
                btn.show();
                btn.setText(Ext.isString(cfg) ? cfg : this.buttonText[name]);
                width += btn.getEl().getWidth() + 15;
            }else{
                btn.hide();
            }
        }, this);
        return width;
    };
};

QFinance.ui.MessageBox.prototype = {
    /**
         * Returns a reference to the underlying {@link Ext.Window} element
         * @return {Ext.Window} The window
         */
    getDialog : function(titleText){
        if(!this.dlg){
            var btns = [];
                
            this.buttons = {};
            Ext.each(this.buttonNames, function(name){
                btns.push(this.buttons[name] = new Ext.Button({
                    text: this.buttonText[name],
                    handler: this.handleButton.createDelegate(this, [name]),
                    hideMode: 'offsets'
                }));
            }, this);
            this.dlg = new Ext.Window({
                autoCreate : true,
                title:titleText,
                resizable:false,
                constrain:true,
                constrainHeader:true,
                minimizable : false,
                maximizable : false,
                stateful: false,
                modal: true,
                shim:true,
                buttonAlign:"center",
                width:400,
                height:100,
                minHeight: 80,
                plain:true,
                footer:true,                    
                closable:true,
                close : function(){
                    if(this.opt && this.opt.buttons && this.opt.buttons.no && !this.opt.buttons.cancel){
                        this.handleButton("no");
                    }else{
                        this.handleButton("cancel");
                    }
                },
                fbar: new Ext.Toolbar({
                    items: btns,
                    enableOverflow: false
                })
            });                
            this.dlg.render(this.opt.renderTo || document.body);                
            this.dlg.getEl().addClass('x-window-dlg');
            this.mask = this.dlg.mask;
            this.bodyEl = this.dlg.body.createChild({
                html:'<div class="ext-mb-icon"></div><div class="ext-mb-content"><span class="ext-mb-text"></span><br /><div class="ext-mb-fix-cursor"><input type="text" class="ext-mb-input" /><textarea class="ext-mb-textarea"></textarea></div></div>'
            });
            this.iconEl = Ext.get(this.bodyEl.dom.firstChild);
            var contentEl = this.bodyEl.dom.childNodes[1];
            this.msgEl = Ext.get(contentEl.firstChild);
            this.textboxEl = Ext.get(contentEl.childNodes[2].firstChild);
            this.textboxEl.enableDisplayMode();
            this.textboxEl.addKeyListener([10,13], function(){
                if(this.dlg.isVisible() && this.opt && this.opt.buttons){
                    if(this.opt.buttons.ok){
                        this.handleButton("ok");
                    }else if(opt.buttons.yes){
                        this.handleButton("yes");
                    }
                }
            });
            this.textareaEl = Ext.get(contentEl.childNodes[2].childNodes[1]);
            this.textareaEl.enableDisplayMode();
            this.progressBar = new Ext.ProgressBar({
                renderTo:this.bodyEl
            });
            this.bodyEl.createChild({
                cls:'x-clear'
            });
        }
        return this.dlg;
    },

    /**
         * Updates the message box body text
         * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
         * the XHTML-compliant non-breaking space character '&amp;#160;')
         * @return {Ext.MessageBox} this
         */
    updateText : function(text){
        if(!this.dlg.isVisible() && !this.opt.width){
            this.dlg.setSize(this.maxWidth, 100); // resize first so content is never clipped from previous shows
        }
        // Append a space here for sizing. In IE, for some reason, it wraps text incorrectly without one in some cases
        this.msgEl.update(text ? text + ' ' : '&#160;');

        var iw = this.iconCls != '' ? (this.iconEl.getWidth() + this.iconEl.getMargins('lr')) : 0,
        mw = this.msgEl.getWidth() + this.msgEl.getMargins('lr'),
        fw = this.dlg.getFrameWidth('lr'),
        bw = this.dlg.body.getFrameWidth('lr'),
        w;
                
        w = Math.max(Math.min(this.opt.width || iw+mw+fw+bw, this.opt.maxWidth || this.maxWidth),
            Math.max(this.opt.minWidth || this.minWidth, bwidth || 0));

        if(this.opt.prompt === true){
            this.activeTextEl.setWidth(w-iw-fw-bw);
        }
        if(this.opt.progress === true || this.opt.wait === true){
            this.progressBar.setSize(w-iw-fw-bw);
        }
        if(Ext.isIE && w == bwidth){
            w += 4; //Add offset when the content width is smaller than the buttons.    
        }
        this.msgEl.update(text || '&#160;');
        this.dlg.setSize(w, 'auto').center();
        return this;
    },

    /**
         * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
         * initiated via {@link Ext.MessageBox#progress} or {@link Ext.MessageBox#wait},
         * or by calling {@link Ext.MessageBox#show} with progress: true.
         * @param {Number} value Any number between 0 and 1 (e.g., .5, defaults to 0)
         * @param {String} progressText The progress text to display inside the progress bar (defaults to '')
         * @param {String} msg The message box's body text is replaced with the specified string (defaults to undefined
         * so that any existing body text will not get overwritten by default unless a new value is passed in)
         * @return {Ext.MessageBox} this
         */
    updateProgress : function(value, progressText, msg){
        this.progressBar.updateProgress(value, progressText);
        if(msg){
            this.updateText(msg);
        }
        return this;
    },

    /**
         * Returns true if the message box is currently displayed
         * @return {Boolean} True if the message box is visible, else false
         */
    isVisible : function(){
        return this.dlg && this.dlg.isVisible();
    },

    /**
         * Hides the message box if it is displayed
         * @return {Ext.MessageBox} this
         */
    hide : function(){
        var proxy = this.dlg ? this.dlg.activeGhost : null;
        if(this.isVisible() || this.proxy){
            this.dlg.hide();
            this.handleHide();
            if (this.proxy){
                // unghost is a private function, but i saw no better solution
                // to fix the locking problem when dragging while it closes
                this.dlg.unghost(false, false);
            } 
        }
        return this;
    },

    /**
         * Displays a new message box, or reinitializes an existing message box, based on the config options
         * passed in. All display functions (e.g. prompt, alert, etc.) on MessageBox call this function internally,
         * although those calls are basic shortcuts and do not support all of the config options allowed here.
         * @param {Object} config The following config options are supported: <ul>
         * <li><b>animEl</b> : String/Element<div class="sub-desc">An id or Element from which the message box should animate as it
         * opens and closes (defaults to undefined)</div></li>
         * <li><b>buttons</b> : Object/Boolean<div class="sub-desc">A button config object (e.g., Ext.MessageBox.OKCANCEL or {ok:'Foo',
         * cancel:'Bar'}), or false to not show any buttons (defaults to false)</div></li>
         * <li><b>closable</b> : Boolean<div class="sub-desc">False to hide the top-right close button (defaults to true). Note that
         * progress and wait dialogs will ignore this property and always hide the close button as they can only
         * be closed programmatically.</div></li>
         * <li><b>cls</b> : String<div class="sub-desc">A custom CSS class to apply to the message box's container element</div></li>
         * <li><b>defaultTextHeight</b> : Number<div class="sub-desc">The default height in pixels of the message box's multiline textarea
         * if displayed (defaults to 75)</div></li>
         * <li><b>fn</b> : Function<div class="sub-desc">A callback function which is called when the dialog is dismissed either
         * by clicking on the configured buttons, or on the dialog close button, or by pressing
         * the return button to enter input.
         * <p>Progress and wait dialogs will ignore this option since they do not respond to user
         * actions and can only be closed programmatically, so any required function should be called
         * by the same code after it closes the dialog. Parameters passed:<ul>
         * <li><b>buttonId</b> : String<div class="sub-desc">The ID of the button pressed, one of:<div class="sub-desc"><ul>
         * <li><tt>ok</tt></li>
         * <li><tt>yes</tt></li>
         * <li><tt>no</tt></li>
         * <li><tt>cancel</tt></li>
         * </ul></div></div></li>
         * <li><b>text</b> : String<div class="sub-desc">Value of the input field if either <tt><a href="#show-option-prompt" ext:member="show-option-prompt" ext:cls="Ext.MessageBox">prompt</a></tt>
         * or <tt><a href="#show-option-multiline" ext:member="show-option-multiline" ext:cls="Ext.MessageBox">multiline</a></tt> is true</div></li>
         * <li><b>opt</b> : Object<div class="sub-desc">The config object passed to show.</div></li>
         * </ul></p></div></li>
         * <li><b>scope</b> : Object<div class="sub-desc">The scope of the callback function</div></li>
         * <li><b>icon</b> : String<div class="sub-desc">A CSS class that provides a background image to be used as the body icon for the
         * dialog (e.g. Ext.MessageBox.WARNING or 'custom-class') (defaults to '')</div></li>
         * <li><b>iconCls</b> : String<div class="sub-desc">The standard {@link Ext.Window#iconCls} to
         * add an optional header icon (defaults to '')</div></li>
         * <li><b>maxWidth</b> : Number<div class="sub-desc">The maximum width in pixels of the message box (defaults to 600)</div></li>
         * <li><b>minWidth</b> : Number<div class="sub-desc">The minimum width in pixels of the message box (defaults to 100)</div></li>
         * <li><b>modal</b> : Boolean<div class="sub-desc">False to allow user interaction with the page while the message box is
         * displayed (defaults to true)</div></li>
         * <li><b>msg</b> : String<div class="sub-desc">A string that will replace the existing message box body text (defaults to the
         * XHTML-compliant non-breaking space character '&amp;#160;')</div></li>
         * <li><a id="show-option-multiline"></a><b>multiline</b> : Boolean<div class="sub-desc">
         * True to prompt the user to enter multi-line text (defaults to false)</div></li>
         * <li><b>progress</b> : Boolean<div class="sub-desc">True to display a progress bar (defaults to false)</div></li>
         * <li><b>progressText</b> : String<div class="sub-desc">The text to display inside the progress bar if progress = true (defaults to '')</div></li>
         * <li><a id="show-option-prompt"></a><b>prompt</b> : Boolean<div class="sub-desc">True to prompt the user to enter single-line text (defaults to false)</div></li>
         * <li><b>proxyDrag</b> : Boolean<div class="sub-desc">True to display a lightweight proxy while dragging (defaults to false)</div></li>
         * <li><b>title</b> : String<div class="sub-desc">The title text</div></li>
         * <li><b>value</b> : String<div class="sub-desc">The string value to set into the active textbox element if displayed</div></li>
         * <li><b>wait</b> : Boolean<div class="sub-desc">True to display a progress bar (defaults to false)</div></li>
         * <li><b>waitConfig</b> : Object<div class="sub-desc">A {@link Ext.ProgressBar#waitConfig} object (applies only if wait = true)</div></li>
         * <li><b>width</b> : Number<div class="sub-desc">The width of the dialog in pixels</div></li>
         * </ul>
         * Example usage:
         * <pre><code>
Ext.Msg.show({
   title: 'Address',
   msg: 'Please enter your address:',
   width: 300,
   buttons: Ext.MessageBox.OKCANCEL,
   multiline: true,
   fn: saveAddress,
   animEl: 'addAddressBtn',
   icon: Ext.MessageBox.INFO
});
</code></pre>
         * @return {Ext.MessageBox} this
         */
    show : function(options){
        if(this.isVisible()){
            this.hide();
        }
        this.opt = options;
        var d = this.getDialog(this.opt.title || "&#160;");

        d.setTitle(this.opt.title || "&#160;");
        var allowClose = (this.opt.closable !== false && this.opt.progress !== true && this.opt.wait !== true);
        d.tools.close.setDisplayed(allowClose);
        this.activeTextEl = this.textboxEl;
        this.opt.prompt = this.opt.prompt || (this.opt.multiline ? true : false);
        if(this.opt.prompt){
            if(this.opt.multiline){
                this.textboxEl.hide();
                this.textareaEl.show();
                this.textareaEl.setHeight(Ext.isNumber(this.opt.multiline) ? this.opt.multiline : this.defaultTextHeight);
                this.activeTextEl = this.textareaEl;
            }else{
                this.textboxEl.show();
                this.textareaEl.hide();
            }
        }else{
            this.textboxEl.hide();
            this.textareaEl.hide();
        }
        this.activeTextEl.dom.value = this.opt.value || "";
        if(this.opt.prompt){
            d.focusEl = this.activeTextEl;
        }else{
            var bs = this.opt.buttons;
            var db = null;
            if(bs && bs.ok){
                db = this.buttons["ok"];
            }else if(bs && bs.yes){
                db = this.buttons["yes"];
            }
            if (db){
                d.focusEl = db;
            }
        }
        if(Ext.isDefined(this.opt.iconCls)){
            d.setIconClass(this.opt.iconCls);
        }
        this.setIcon(Ext.isDefined(this.opt.icon) ? this.opt.icon : this.bufferIcon);
        bwidth = this.updateButtons(this.opt.buttons);
        this.progressBar.setVisible(this.opt.progress === true || this.opt.wait === true);
        this.updateProgress(0, this.opt.progressText);
        this.updateText(this.opt.msg);
        if(this.opt.cls){
            d.el.addClass(opt.cls);
        }
        d.proxyDrag = this.opt.proxyDrag === true;
        d.modal = this.opt.modal !== false;
        d.mask = this.opt.modal !== false ? this.mask : true;
        if(!d.isVisible()){
            // force it to the end of the z-index stack so it gets a cursor in FF
            if (this.opt.renderTo)
                this.opt.renderTo.appendChild(this.dlg.el.dom);
            else
                document.body.appendChild(this.dlg.el.dom);
            d.setAnimateTarget(this.opt.animEl);
            //workaround for window internally enabling keymap in afterShow
            d.on('show', function(){
                if(allowClose === true){
                    d.keyMap.enable();
                }else{
                    d.keyMap.disable();
                }
            }, this, {
                single:true
            });
            d.show(this.opt.animEl);
        }
        if(this.opt.wait === true){
            this.progressBar.wait(this.opt.waitConfig);
        }
        return this;
    },

    /**
         * Adds the specified icon to the dialog.  By default, the class 'ext-mb-icon' is applied for default
         * styling, and the class passed in is expected to supply the background image url. Pass in empty string ('')
         * to clear any existing icon. This method must be called before the MessageBox is shown.
         * The following built-in icon classes are supported, but you can also pass in a custom class name:
         * <pre>
Ext.MessageBox.INFO
Ext.MessageBox.WARNING
Ext.MessageBox.QUESTION
Ext.MessageBox.ERROR
         *</pre>
         * @param {String} icon A CSS classname specifying the icon's background image url, or empty string to clear the icon
         * @return {Ext.MessageBox} this
         */
    setIcon : function(icon){
        if(!this.dlg){
            this.bufferIcon = icon;
            return;
        }
        this.bufferIcon = undefined;
        if(icon && icon != ''){
            this.iconEl.removeClass('x-hidden');
            this.iconEl.replaceClass(this.iconCls, icon);
            this.bodyEl.addClass('x-dlg-icon');
            this.iconCls = icon;
        }else{
            this.iconEl.replaceClass(this.iconCls, 'x-hidden');
            this.bodyEl.removeClass('x-dlg-icon');
            this.iconCls = '';
        }
        return this;
    },

    /**
         * Displays a message box with a progress bar.  This message box has no buttons and is not closeable by
         * the user.  You are responsible for updating the progress bar as needed via {@link Ext.MessageBox#updateProgress}
         * and closing the message box when the process is complete.
         * @param {String} title The title bar text
         * @param {String} msg The message box body text
         * @param {String} progressText (optional) The text to display inside the progress bar (defaults to '')
         * @return {Ext.MessageBox} this
         */
    progress : function(title, msg, progressText){
        this.show({
            title : title,
            msg : msg,
            buttons: false,
            progress:true,
            closable:false,
            minWidth: this.minProgressWidth,
            progressText: progressText
        });
        return this;
    },

    /**
         * Displays a message box with an infinitely auto-updating progress bar.  This can be used to block user
         * interaction while waiting for a long-running process to complete that does not have defined intervals.
         * You are responsible for closing the message box when the process is complete.
         * @param {String} msg The message box body text
         * @param {String} title (optional) The title bar text
         * @param {Object} config (optional) A {@link Ext.ProgressBar#waitConfig} object
         * @return {Ext.MessageBox} this
         */
    wait : function(msg, title, config){
        this.show({
            title : title,
            msg : msg,
            buttons: false,
            closable:false,
            wait:true,
            modal:true,
            minWidth: this.minProgressWidth,
            waitConfig: config
        });
        return this;
    },

    /**
         * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript alert prompt).
         * If a callback function is passed it will be called after the user clicks the button, and the
         * id of the button that was clicked will be passed as the only parameter to the callback
         * (could also be the top-right close button).
         * @param {String} title The title bar text
         * @param {String} msg The message box body text
         * @param {Function} fn (optional) The callback function invoked after the message box is closed
         * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to the browser wnidow.
         * @return {Ext.MessageBox} this
         */
    alert : function(title, msg, fn, scope){
        this.show({
            title : title,
            msg : msg,
            buttons: this.OK,
            fn: fn,
            scope : scope,
            minWidth: this.minWidth
        });
        return this;
    },

    /**
         * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's confirm).
         * If a callback function is passed it will be called after the user clicks either button,
         * and the id of the button that was clicked will be passed as the only parameter to the callback
         * (could also be the top-right close button).
         * @param {String} title The title bar text
         * @param {String} msg The message box body text
         * @param {Function} fn (optional) The callback function invoked after the message box is closed
         * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to the browser wnidow.
         * @return {Ext.MessageBox} this
         */
    confirm : function(title, msg, fn, scope){
        this.show({
            title : title,
            msg : msg,
            buttons: this.YESNO,
            fn: fn,
            scope : scope,
            icon: this.QUESTION,
            minWidth: this.minWidth
        });
        return this;
    },

    /**
         * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to JavaScript's prompt).
         * The prompt can be a single-line or multi-line textbox.  If a callback function is passed it will be called after the user
         * clicks either button, and the id of the button that was clicked (could also be the top-right
         * close button) and the text that was entered will be passed as the two parameters to the callback.
         * @param {String} title The title bar text
         * @param {String} msg The message box body text
         * @param {Function} fn (optional) The callback function invoked after the message box is closed
         * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to the browser wnidow.
         * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
         * property, or the height in pixels to create the textbox (defaults to false / single-line)
         * @param {String} value (optional) Default value of the text input element (defaults to '')
         * @return {Ext.MessageBox} this
         */
    prompt : function(title, msg, fn, scope, multiline, value){
        this.show({
            title : title,
            msg : msg,
            buttons: this.OKCANCEL,
            fn: fn,
            minWidth: this.minPromptWidth,
            scope : scope,
            prompt:true,
            multiline: multiline,
            value: value
        });
        return this;
    },

    /**
         * Button config that displays a single OK button
         * @type Object
         */
    OK : {
        ok:true
    },
    /**
         * Button config that displays a single Cancel button
         * @type Object
         */
    CANCEL : {
        cancel:true
    },
    /**
         * Button config that displays OK and Cancel buttons
         * @type Object
         */
    OKCANCEL : {
        ok:true, 
        cancel:true
    },
    /**
         * Button config that displays Yes and No buttons
         * @type Object
         */
    YESNO : {
        yes:true, 
        no:true
    },
    /**
         * Button config that displays Yes, No and Cancel buttons
         * @type Object
         */
    YESNOCANCEL : {
        yes:true, 
        no:true, 
        cancel:true
    },
    /**
         * The CSS class that provides the INFO icon image
         * @type String
         */
    INFO : 'ext-mb-info',
    /**
         * The CSS class that provides the WARNING icon image
         * @type String
         */
    WARNING : 'ext-mb-warning',
    /**
         * The CSS class that provides the QUESTION icon image
         * @type String
         */
    QUESTION : 'ext-mb-question',
    /**
         * The CSS class that provides the ERROR icon image
         * @type String
         */
    ERROR : 'ext-mb-error',

    /**
         * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
         * @type Number
         */
    defaultTextHeight : 75,
    /**
         * The maximum width in pixels of the message box (defaults to 600)
         * @type Number
         */
    maxWidth : 600,
    /**
         * The minimum width in pixels of the message box (defaults to 100)
         * @type Number
         */
    minWidth : 100,
    /**
         * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful
         * for setting a different minimum width than text-only dialogs may need (defaults to 250).
         * @type Number
         */
    minProgressWidth : 250,
    /**
         * The minimum width in pixels of the message box if it is a prompt dialog.  This is useful
         * for setting a different minimum width than text-only dialogs may need (defaults to 250).
         * @type Number
         */
    minPromptWidth: 250,
    /**
         * An object containing the default button text strings that can be overriden for localized language support.
         * Supported properties are: ok, cancel, yes and no.  Generally you should include a locale-specific
         * resource file for handling language support across the framework.
         * Customize the default text like so: Ext.MessageBox.buttonText.yes = "oui"; //french
         * @type Object
         */
    buttonText : {
        ok : "OK",
        cancel : "Cancel",
        yes : "Yes",
        no : "No"
    }
};
/**
 * @depends ui.js
 */
QFinance.ui.Window = Ext.extend( Ext.Window, {   
    // Localization
    waitingMessageSingular: 'Processing {0} item.',
    waitingMessagePlural: 'Processing {0} items.',
    errorMessageTitle: 'Processing error',
    infoMessageTitle: 'Processing info',
    
    initComponent: function() {    
        Ext.applyIf(this, {
            processStatusManager: new QFinance.ui.ProcessStatusManager()
        });

        if (this.ownerWindow) {
            Ext.apply(this, {
                renderTo: this.ownerWindow.body,
                modal: true,
                constrain: true                
            });
            this.ownerWindow.on('restore', function(window) {                
                this.doConstrain();
            }, this);
        }
        Ext.apply(this, {
            bbar: new QFinance.ui.StatusBar(this.bbar)
        });
                
        this.processStatusManager.on('statusupdate', this.onStatusUpdate, this);        
        
        QFinance.ui.Window.superclass.initComponent.call(this);
        
        this.doInitStatusBar();
    },
    
    doInitStatusBar: function() {
        if (this.initStatusBar)
            this.initStatusBar( this.bottomToolbar );
        var panels = this.findByType('qpanel');
        Ext.each(panels, function(component) {
            if (component.initStatusBar)
                component.initStatusBar( this.bottomToolbar ); 
        }, this);
    },
    
    getProcessStatusManager: function() {
        return this.processStatusManager;
    },
    
    setProcessStatusManager: function(processStatusManager) {
        this.processStatusManager = processStatusManager;
    },
    
    showErrorMessageBox: function(title, message) {
        var messageBox = new QFinance.ui.MessageBox();
        messageBox.show({					
            title: title,
            buttons: messageBox.OK,
            icon: messageBox.ERROR,
            msg: message,
            renderTo: this.body,                
            modal: true,
            minWidth: 200,
            scope: this
        });   
    },
    
    showInfoMessageBox: function(title, message) {
        var messageBox = new QFinance.ui.MessageBox();
        messageBox.show({					
            title: title,
            buttons: messageBox.OK,
            icon: messageBox.INFO,
            msg: message,
            renderTo: this.body,                
            modal: true,
            minWidth: 200,
            scope: this
        });    
    },
    
    onStatusUpdate: function(processStatusManager, processes) {                
        var runningCount = 0;
        var componentsToDisable = [];
        Ext.each(processes, function(process) {
            if (process.status == QFinance.ui.ProcessStatusManager.STARTED) {                                
                // Status count
                runningCount++;
                // Disabled components
                Ext.each(process.components, function(component) {
                    if (componentsToDisable.indexOf(component) == -1)
                        componentsToDisable.push(component);
                });
            }
        });

        // Update toolbar message e components status
        if (this.rendered) {
            if (runningCount > 0) {
                var busyMessage = '';
                busyMessage = runningCount == 1 ? String.format(this.waitingMessageSingular, runningCount) : String.format(this.waitingMessagePlural, runningCount)
                this.bottomToolbar.showBusy(busyMessage);
            } else {
                this.bottomToolbar.clear();
            }
                                    
            Ext.each(componentsToDisable, function(component) {
                if (component && component.rendered) {
                    if (component.isXType('window')) {                   
                        component.body.mask();
                        if (component.topToolbar && component.topToolbar.getEl()) {
                            component.topToolbar.getEl().mask();
                        }
                    } else if (component.isXType('container')) {
                        component.getEl().mask();
                    } else {
                        component.disable();
                    }
                }
            });
        }
        
        if (runningCount == 0) {
            var endedSuccessfullCount = 0;
            var endedErrorfullCount = 0;
            var errorMessage = '';
            var infoMessage = '';
            var componentsToEnable = []; 
            componentsToDisable = [];
            Ext.each(processes, function(process) {
                if (process.status == QFinance.ui.ProcessStatusManager.ENDED) {                
                    // Status count
                    endedSuccessfullCount++;                
                    // Message
                    if (process.message && !process.showed) {
                        if (infoMessage.length > 0)
                            infoMessage += '<br>';
                        infoMessage += process.message;
                        process.showed = true;
                    }
                    // Enabled components
                    Ext.each(process.components, function(component) {
                        if (componentsToEnable.indexOf(component) == -1)
                            componentsToEnable.push(component);
                    });                
                } else if (process.status == QFinance.ui.ProcessStatusManager.ERROR) {                
                    // Status count
                    endedErrorfullCount++
                    // Message
                    if (process.message && !process.showed) {
                        if (errorMessage.length > 0)
                            errorMessage += '<br>';
                        errorMessage += process.message; 
                        process.showed = true;
                    }
                    // Enabled components
                    Ext.each(process.components, function(component) {
                        if (componentsToDisable.indexOf(component) == -1)
                            componentsToDisable.push(component);
                    });
                }
            });
            
            if (this.rendered) {
                // Update components status
                Ext.each(componentsToEnable, function(component) {
                    if (component && component.rendered) {
                        if (component.isXType('window')) {                   
                            component.body.unmask();
                            if (component.topToolbar && component.topToolbar.getEl()) {
                                component.topToolbar.getEl().unmask();
                            }
                        } else if (component.isXType('container')) {
                            component.getEl().unmask();
                        } else {
                            component.enable();
                        }
                    }
                });   
            }
            
            var showErrorMessage = function() {           
                var messageBox = new QFinance.ui.MessageBox();
                messageBox.show({					
                    title: this.errorMessageTitle,
                    buttons: messageBox.OK,
                    icon: messageBox.ERROR,
                    msg: errorMessage,
                    renderTo: this.body,                
                    modal: true,
                    minWidth: 200,
                    scope: this,
                    fn: function() {
                        Ext.each(componentsToDisable, function(component) {
                            if (component && component.rendered) {
                                if (component.isXType('window')) {                   
                                    component.body.mask();
                                    if (component.topToolbar && component.topToolbar.getEl()) {
                                        component.topToolbar.getEl().mask();
                                    }
                                } else if (component.isXType('container')) {
                                    component.getEl().mask();
                                } else {
                                    component.disable();
                                }
                            }
                        });
                    }
                });   
            };

            var showInfoMessage = function() {            
                var messageBox = new QFinance.ui.MessageBox();
                messageBox.show({					
                    title: this.infoMessageTitle,
                    buttons: messageBox.OK,
                    icon: messageBox.INFO,
                    msg: infoMessage,
                    renderTo: this.body,                
                    modal: true,
                    minWidth: 200,
                    scope: this
                });    
            };

            if (this.rendered) {
                if (errorMessage.length > 0)
                    showErrorMessage.call(this);
                if (infoMessage.length > 0)
                    showInfoMessage.call(this);
            } else {
                if (errorMessage.length > 0)
                    this.on('show', showErrorMessage);
                if (infoMessage.length > 0)
                    this.on('show', showInfoMessage);
            }
        } 
    }
});
Ext.reg('qwindow', QFinance.ui.Window);
/**
 * @depends portlet.js, Window.js
 */
QFinance.portlet.TopAmountPortletConfigurationWindow = Ext.extend( QFinance.ui.Window, {
    formPanel: null,
    comboBoxTopType: null,
    configuration: {
        topType: 1
    },
	
    // Localization
    labelWidth: 90,
    title: 'Top amount portlet configuration',	
    amountTypeText: 'Amount type',
    amountTypeEmptyText: 'Select an type',
    categoryText: 'Category',
    accountText: 'Account',
    transactionText: 'Transaction',
    markText: 'Mark',
    saveText: 'Save',
    closeText: 'Close',
	
    constructor: function(cfg) {
        Ext.apply(this, cfg);
		
        this.addEvents(['save']);
		
        QFinance.portlet.TopAmountPortletConfigurationWindow.superclass.constructor.call(this);
    },
	
    initComponent: function() {	
        Ext.apply(this, {
            width: 300,
            items: [ this.formPanel = new Ext.form.FormPanel({
                frame: true,
                autoHeight: true,
                defaultType: 'textfield',
                defaults: {
                    anchor: '100%'
                },
                labelWidth: this.labelWidth,
                items: [ this.comboBoxTopType = new Ext.form.ComboBox({
                    xtype: 'combo',
                    fieldLabel: this.amountTypeText,
                    name: 'amountType',    		
                    typeAhead: true,
                    triggerAction: 'all',
                    emptyText: this.amountTypeEmptyText,
                    selectOnFocus: true,
                    forceSelection: true,
                    allowBlank: false,
                    value: this.configuration.topType,
                    store: [
                    ['1', this.categoryText],
                    ['2', this.accountText],
                    ['3', this.transactionText],
                    ['4', this.markText]
                    ]    	     
                })]
            })]
        });
        QFinance.portlet.TopAmountPortletConfigurationWindow.superclass.initComponent.call(this);
    },
	
    initStatusBar: function(toolbar) {
        toolbar.add(new Ext.Button({
            text: this.saveText,
            formBind: true,
            scope: this,
            iconCls: 'fugue-disk-black',
            handler: function() {
                if (this.formPanel.getForm().isValid()) {
                    this.doSave();	 
                    this.close();
                }
            }
        }));
				
        toolbar.add(new Ext.Button({
            text: this.closeText,
            iconCls: 'fugue-door-open-out',				
            scope: this,
            handler: function() {
                this.close();
            }
        }));
    },
	
    doSave: function() {
        this.configuration.topType = this.comboBoxTopType.getValue();			
        this.fireEvent('save', this.configuration);
    }
});
Ext.reg('QFinance.portlet.TopAmountPortletConfigurationWindow', QFinance.portlet.TopAmountPortletConfigurationWindow);
/**
 * @depends portlet.js, Window.js
 */
QFinance.portlet.AccountsBalanceHistoryConfigurationWindow = Ext.extend( QFinance.ui.Window, {
    // Default configuration
    configuration: {
        accountID: 0,
        range: 2,
        startDate: null,
        endDate: null,
        type: 1
    },
	
    // Localization
    title: 'Accounts balance history configuration',	
    accountText: 'Account',
    allTimeText: 'All time',
    past30DaysText: 'Past 30 days',
    past60DaysText: 'Past 60 days',
    thisMonthText: 'This month',
    thisYearText: 'This year',
    customText: 'Custom',
    rangeText: 'Range',
    bothText: 'Both',
    incomeText: 'Income',
    expenseText: 'Expense',
    typeText: 'Type',	
    saveText: 'Save',
    closeText: 'Close',
	
    constructor: function(cfg) {
        Ext.apply(this, cfg);
		
        QFinance.portlet.AccountsBalanceHistoryConfigurationWindow.superclass.constructor.call(this);
    },
	
    initComponent: function() {
        this.items = [];
        this.initWindow();        
        this.initStore();
        this.initFormPanel();
        QFinance.portlet.AccountsBalanceHistoryConfigurationWindow.superclass.initComponent.call(this);
    },
	
    initWindow: function() {
        Ext.apply(this, {
            width: 300,
            height: 300,
            autoHeight: true
        });
    },
	
    initStatusBar: function(toolbar) {
        toolbar.add(new Ext.Button({
            text: this.saveText,
            formBind: true,
            scope: this,
            iconCls: 'fugue-disk-black',
            handler: function() {
                if (this.formPanel.getForm().isValid()) {
                    this.doSave();	 
                    this.close();
                }
            }
        }));
				
        toolbar.add(new Ext.Button({
            text: this.closeText,
            iconCls: 'fugue-door-open-out',				
            scope: this,
            handler: function() {
                this.close();
            }
        }));
    },
	
    initStore: function() {
        this.accountStore = new Ext.data.DirectStore({    		
            directFn: QFinance.Remoting.AccountAction.getByAccountTypePlusAll,
            paramsAsHash: false,
            autoLoad: true,
            idProperty: 'id',
            root: 'data',
            successProperty: 'success',
            paramOrder: [ 'type' ],
            baseParams: {
                type: '1'
            },
            fields: [
            {
                name: 'id',
                type: 'int',
                useNull: true
            },
            {
                name: 'accountName'	    		    
            },
            {
                name: 'accountType'
            }
            ],
            listeners: {
                scope: this,
                beforeload: function(store, options) {
                    store.id = this.getProcessStatusManager().start([this]);
                },				
                load: function(store, records, options) {
                    this.getProcessStatusManager().success(store.id);
                    this.accountCombo.setValue(this.configuration.accountID);
                    var range = this.configuration.range;
                    if (range != 5) {
                        this.rangeCompositeField.items.each(function(f){
                            f.clearInvalid();
                        });
                    }
                    this.rangeCombo.setValue(range);
                },
                exception: function(dataProxy, type, action, options, response, arg ) {
                    var message = '';
                    var where = '';
                    if (response.result) {
                        message = response.result.message;
                        if (response.result.type == 'exception')
                            where = response.result.where;
                    } else {
                        message = response.message;
                    }
                    this.getProcessStatusManager().error(this.accountStore.id, message);
                    QFinance.service.DeveloperService.log('Store failure: ' + message + ' where\n' + where);
                }
            }		
        });		
    },
	
    initFormPanel: function() {
        this.items.push( this.formPanel = new Ext.form.FormPanel({
            xtype: 'form',
            frame: true,
            labelWidth: 60,
            defaults: {
                anchor: '100%'
            },
            items: [ this.accountCombo = new Ext.form.ComboBox({
                name: 'accountID',
                store: this.accountStore,
                fieldLabel: this.accountText,
                autoSelect: true,
                editable: false,
                triggerAction: 'all',		      		    
                valueField: 'id',
                displayField: 'accountName',
                mode: 'local',
                listeners: {
                    scope: this,
                    select: function(combo, record, index) {
                        this.typeCombo.setDisabled( index == 0 );		              				
                    }
                }
            }), this.rangeCombo = new Ext.form.ComboBox({			        	
                name: 'range',
                store: [ 
                [ 1, this.allTimeText ],
                [ 2, this.past30DaysText ],
                [ 3, this.past60DaysText ],
                [ 4, this.thisMonthText ],
                [ 5, this.thisYearText ],
                [ 6, this.customText ]
                ],
                fieldLabel: this.rangeText,
                autoSelect: true,		            	
                editable: false,
                triggerAction: 'all',		      		    		              	
                mode: 'local',
                hiddenName: 'range',              	
                listeners: {
                    scope: this,
                    select: function(combo, record, index) {		              					              			
                        if (index != 5)
                            this.rangeCompositeField.items.each(function(f){
                                f.clearInvalid();
                            });
              				
              			
                        this.rangeCompositeField.setDisabled( index != 5 );
                    }
                }
            }), this.rangeCompositeField = new Ext.form.CompositeField({
                xtype: 'compositefield',
                disabled: true,
                defaults: {
                    flex: 1
                },
                items: [ this.startDateField = new Ext.form.DateField({
                    xtype: 'datefield',
                    name: 'startDate',
                    id: 'startDate',
                    format: "Y-m-d",
                    vtype: 'daterangecomposite',
                    endDateField: 'endDate',
                    allowBlank: false,
                    value: this.configuration.startDate
                }), this.endDateField = new Ext.form.DateField({
                    xtype: 'datefield',
                    name : 'endDate',
                    id: 'endDate',
                    format: "Y-m-d",
                    vtype: 'daterangecomposite',
                    startDateField: 'startDate',
                    allowBlank: false,
                    value: this.configuration.endDate
                })]
            }), this.typeCombo = new Ext.form.ComboBox({			        	
                name: 'type',
                store: [ 
                [ 1, this.bothText ],
                [ 2, this.incomeText ],
                [ 3, this.expenseText ]
                ],
                disabled: true,
                fieldLabel: this.typeText,
                autoSelect: true,		            	
                editable: false,
                triggerAction: 'all',		      		    		              	
                mode: 'local',
                hiddenName: 'type',
                value: this.configuration.type
            })]
        }));
    },
	
    doSave: function() {
        this.configuration.accountID = this.accountCombo.getValue();
        this.configuration.accountName = this.accountCombo.getRawValue();
        this.configuration.range = this.rangeCombo.getValue();
        this.configuration.rangeName = this.rangeCombo.getRawValue();
        this.configuration.startDate = this.startDateField.getValue();
        this.configuration.endDate = this.endDateField.getValue();
        this.configuration.type = this.typeCombo.getValue();
        this.configuration.typeName = this.typeCombo.getRawValue();
        this.fireEvent('save', this.configuration);
    }
});

Ext.reg('QFinance.portlet.AccountsBalanceHistoryConfigurationWindow', QFinance.portlet.AccountsBalanceHistoryConfigurationWindow);
/*
 * @depends module.js, Window.js
 */
QFinance.module.TransactionsModule = Ext.extend(QFinance.module.Module, {
    // Configuration
    id: 'QFinance.module.TransactionsModule',	
	
    // Localization
    transactionsText: 'Transactions',
    selectAccountText: 'Select an account:',
    closeText: 'Close',
    
    // Components
    transactionsEditPanel: null,
    accountStore: null,
    
    init : function(){
        this.launcher = {
            text: this.transactionsText,
            iconCls: 'fugue-moneys',
            handler: this.createWindow,
            scope: this
        };        
    },
    createWindow : function(){		
        var desktop = this.app.getDesktop();
        var win = desktop.getWindow('QFinance.module.TransactionsModule.createWindow.win');
        if (!win){
            this.accountStore = new Ext.data.DirectStore({    		
                directFn: QFinance.Remoting.AccountAction.getByAccountType,
                paramsAsHash: false,
                autoLoad: false,
                paramOrder: [ 'type' ],
                baseParams: {
                    type: '1'
                },
                idProperty: 'id',
                root: 'data',
                successProperty: 'success',
                fields: [
                {
                    name: 'id',
                    type: 'int'
                },
                {
                    name: 'accountName'	    		    
                },
                {
                    name: 'accountType'
                }
                ],
                listeners: {
                    scope: this,
                    beforeload: function(store, options) {
                        store.id = win.processStatusManager.start([win.topToolbar]);
                    },				
                    load: function(store, records, options) {
                        win.processStatusManager.success(store.id);
                    },				
                    exception: function(dataProxy, type, action, options, response, arg ) {
                        var message = '';
                        var where = '';
                        if (response.result) {
                            message = response.result.message;
                            if (response.result.type == 'exception')
                                where = response.result.where;
                        } else {
                            message = response.message;
                        }
                        win.processStatusManager.error(this.accountStore.id, message);
                        QFinance.service.DeveloperService.log('Store failure: ' + message + ' where\n' + where);
                    }
                }   		
            });
            win = desktop.createWindow({
                id: 'QFinance.module.TransactionsModule.createWindow.win',
                title: this.transactionsText,
                width: 740,
                height: 480,
                iconCls: 'fugue-moneys',
                animCollapse: false,
                layout: 'fit',
                items: [this.transactionsEditPanel = new QFinance.component.TransactionsEditPanel({
                    showAccountOverview: true,
                    showAccountBalance: true
                })],
                tbar: [
                this.selectAccountText,
                {
                    xtype: 'combo',
                    store: this.accountStore,
                    typeAhead: true,
                    triggerAction: 'all',
                    selectOnFocus: true,
                    valueField: 'id',
                    displayField: 'accountName',
                    mode: 'local',
                    listeners: {
                        scope: this,
                        select: function(comboBox, record, index) {	              			
                            this.transactionsEditPanel.contextAccountID = record.get('id');
                            this.transactionsEditPanel.load();
                            this.transactionsEditPanel.enable();
                        }
                    }
                }],
                listeners: {
                    scope: this,
                    show: function() {
                        this.transactionsEditPanel.disable();
                        this.accountStore.load(this);
                    }
                },
                bbar:  [new Ext.Button({
                    text: this.closeText,
                    iconCls: 'fugue-door-open-out',	
                    handler: function() {
                        win.close();				
                    }
                })],
                stateful: true
            },QFinance.ui.Window);
        }
        win.show();
    }
});
/*
 * @depends module.js, Window.js
 */
QFinance.module.CategoriesModule = Ext.extend(QFinance.module.Module, {
    // Configuration
    id: 'QFinance.module.CategoriesModule',
    
    // Localization
    categoriesText: 'Categories',
    closeText: 'Close',
    
    init : function(){
        this.launcher = {
            text: this.categoriesText,
            iconCls: 'fugue-category',
            handler: this.createWindow,
            scope: this
        };
    },
    
    createWindow : function(){		
        var desktop = this.app.getDesktop();
        var win = desktop.getWindow('QFinance.module.CategoriesModule.createWindow.win');
        if(!win){	
            win = desktop.createWindow({
                id: 'QFinance.module.CategoriesModule.createWindow.win',
                title: this.categoriesText,
                width: 480,
                height: 300,
                iconCls: 'fugue-category',
                animCollapse: false,
                layout: 'fit',	            
                items: [ 
                new QFinance.component.CategoriesEditPanel({
                    canEditCategory: true
                })
                ],
                bbar: [new Ext.Button({
                    text: this.closeText,
                    iconCls: 'fugue-door-open-out',	    		
                    handler: function() {
                        win.close();
                    }
                })],
                stateful: true
            }, QFinance.ui.Window);
        }
        win.show();
    }
});
/*
 * @depends component.js, Window.js
 */
QFinance.component.UserEditWindow = Ext.extend( QFinance.ui.Window, {	
    // Configuration
    isNew: true,
    record: null,
    autoLoadRecord: false,
    savable: true,
	
    // Localization	
    defaultTitleText: 'Editing a new user',
    editingTitleText: 'Editing user: {0}',
    idText: 'ID',
    userNameText: 'User name',
    passwordText: 'Password',
    passwordCheckText: 'Re-type password',
    saveText: 'Save',
    closeText: 'Close',
	
    // Components
    formPanel: null,

    constructor: function(config) {
        Ext.apply(this, config);
		
        this.title = this.defaultTitleText;
		
        Ext.applyIf(this, {
            width: 300,
            autoHeight: true
        });
		
        this.addEvents(['save']);
		
        QFinance.component.UserEditWindow.superclass.constructor.call(this);
    },
	
    initComponent: function() {
        var formPanelConfig = this.getFormPanelConfig();
        this.formPanel = new Ext.form.FormPanel(formPanelConfig);
						
        Ext.apply(this, {
            layout: 'fit',
            items: [this.formPanel]
        });	
		
        if (this.autoLoadRecord && this.record)
            this.loadRecord();
		
        QFinance.component.UserEditWindow.superclass.initComponent.call(this);
    },
	
    initStatusBar: function(toolbar) {	
        if (this.savable) {
            toolbar.add(new Ext.Button({
                text: this.saveText,
                formBind: true,
                scope: this,
                iconCls: 'fugue-disk-black',
                handler: function() {
                    if (this.formPanel.getForm().isValid()) {
                        this.doSave();	 
                        this.close();
                    }
                }
            }));
        }
				
        toolbar.add(new Ext.Button({
            text: this.closeText,
            iconCls: 'fugue-door-open-out',				
            scope: this,
            handler: function() {
                this.close();
            }
        }));
    },
	
    getFormPanelConfig: function() {
        var formPanelConfig = {
            frame: true,
            autoHeight: true,
            defaultType: 'textfield',
            defaults: {
                anchor: '100%'
            },
            labelWidth: 90,
            items: this.getFormPanelItems()
        };
		
        return formPanelConfig;
    },
	
    getFormPanelItems: function() {
        var formPanelItems = [{
            fieldLabel: this.idText,
            name: 'id',
            readOnly: true
        },{
            fieldLabel: this.userNameText,
            name: 'username',    		
            allowBlank: false
        },{
            fieldLabel: this.passwordText,
            id: 'newPassword',
            name: 'newPassword',
            allowBlank: true,
            inputType: 'password'
        },{
            fieldLabel: this.passwordCheckText,
            name: 'newPasswordCheck',
            matches: 'newPassword',
            vtype: 'password',
            allowBlank: false,
            inputType: 'password'
        }];
		
        return formPanelItems;
    },
	
    doSave: function() {
        this.formPanel.getForm().updateRecord( this.record );		
        this.fireEvent('save', this.record);
    },	
	
    loadRecord: function() {
        if (!this.isNew)
            this.setTitle(String.format(this.editingTitleText, this.record.get('username')));
        this.formPanel.getForm().loadRecord( this.record );
    }
});
Ext.reg('QFinance.component.UserEditWindow', QFinance.component.UserEditWindow);
/*
 * @depends component.js, Window.js
 */
QFinance.component.TransactionsEditWindow = Ext.extend( QFinance.ui.Window, {
    // Localization
    closeText: 'Close',
	
    constructor: function(config) {
        Ext.apply(this, config);
		
        QFinance.component.TransactionsEditWindow.superclass.constructor.call(this);
    },
	
    initComponent: function() {
        Ext.apply(this.transactionsEditPanelConfig, {
            listeners: {		
                scope: this,
                close: function() {
                    this.close();
                }
            }
        });
                
        var transactionsEditPanel = new QFinance.component.TransactionsEditPanel(this.transactionsEditPanelConfig);
		
        Ext.applyIf(this,{
            width: 400,
            height: 400
        });
		
        Ext.apply(this, {
            layout: 'fit',
            items: [transactionsEditPanel],
            bbar: [{
                text: this.closeText,
                iconCls: 'fugue-door-open-out',	
                scope: this,
                handler: function() {				
                    this.close();					
                }
            }]
        });
		
        QFinance.component.TransactionsEditWindow.superclass.initComponent.call(this);        
    }
});
Ext.reg('QFinance.component.TransactionsEditWindow', QFinance.component.TransactionsEditWindow);
/*
 * @depends component.js, Window.js
 */
QFinance.component.TransactionMultiEditWindow = Ext.extend( QFinance.ui.Window, {
    // Configuration    
    canChangeSourceAccount: true,
    canChangeDestinationAccount: true,
    canChangeCategory: true,
    accountEditMode: 'both',
    contextAccountID: null,	
    records: null,
    requireCategory: true,
	
    // Localization
    saveText: 'Save',
    closeText: 'Close',    
    accountEmptyText: 'Select a account',
    sourceAccountText: 'Source account',
    destinationAccountText: 'Destination account',    
    defaultTitleText: 'Edit multiple transactions',
    pleaseSelectAnCategory: 'Please, select an category.',
    fillRequiredFields: 'Please, fill required fields.',
    formValidationTitleText: 'Form validation',  
    reloadDataText: 'Reload data',
    categoryText: 'Category',
		
    // Components
    accountStore: null,
    formPanel: null,
    categoryPanel: null,
    sourceComboBox: null,
    destinationComboBox: null,
	
    constructor: function(config) {
        Ext.apply(this,config);
		
        this.accountStore = new Ext.data.DirectStore({
            storeId: 'account-store',
            directFn: QFinance.Remoting.AccountAction.getAccountsMinus,
            paramsAsHash: false,
            idProperty: 'id',
            root: 'data',
            successProperty: 'success',
            paramOrder: [ 'excludeAccount' ],
            baseParams: {
                excludeAccount: this.contextAccountID
            },
            fields: [
            {
                name: 'id',
                type: 'int'
            },
            {
                name: 'accountName'	    		    
            },
            {
                name: 'accountType'
            }
            ],
            listeners: {
                scope: this,
                beforeload: function(store, options) {
                    var components = [];
                    if (this.sourceComboBox)
                        components.push(this.sourceComboBox);
                    if (this.destinationComboBox)
                        components.push(this.destinationComboBox);
                    store.id = this.getProcessStatusManager().start(components);
                    delete components;
                },				
                load: function(store, records, options) {
                    this.getProcessStatusManager().success(store.id);
                },			
                exception: function(dataProxy, type, action, options, response, arg ) {
                    var message = '';
                    var where = '';
                    if (response.result) {
                        message = response.result.message;
                        if (response.result.type == 'exception')
                            where = response.result.where;
                    } else {
                        message = response.message;
                    }
                    this.getProcessStatusManager().error(this.accountStore.id, message);                    
                    QFinance.service.DeveloperService.log('Store failure: ' + message + ' where\n' + where);
                }
            }		
        });
		
        this.addEvents(['save']);
		
        Ext.applyIf(this, {
            width: 400,
            height: 400
        });
		
        QFinance.component.TransactionMultiEditWindow.superclass.constructor.call(this);
    },
	
    show: function() {		
        QFinance.component.TransactionMultiEditWindow.superclass.show.call(this);
						        
        this.accountStore.load();	
    },

    initComponent: function() {		
        var formPanelConfig = this.getFormPanelConfig();
        this.formPanel = new Ext.form.FormPanel(formPanelConfig);
						
        Ext.apply(this,{
            title: this.defaultTitleText,
            layout: 'vbox',
            bodyStyle:'padding: 5px',
            layoutConfig: {
                align : 'stretch',
                pack  : 'start'
            },	
            items: [ this.formPanel, {
                xtype: 'fieldset',
                title: this.categoryText,
                layout: 'fit',
                flex: 1,
                items: [ this.categoryPanel = new QFinance.component.CategoriesEditPanel({
                    disabled: !this.canChangeCategory,
                    autoSelectCategoryID: (this.record && this.record.get('categoryID') > 0) ? this.record.get('categoryID') : 'root',
                    ownerWindow: this
                })]
            }],
            tbar: [{
                text: this.reloadDataText,
                iconCls: 'fugue-arrow-circle',
                scope: this,
                handler: this.doRefreshData
            }]
        });		
		
        QFinance.component.TransactionMultiEditWindow.superclass.initComponent.call(this);
    },    
    
    initStatusBar: function(toolbar) {
        toolbar.add(new Ext.Button({
            text: this.saveText,
            iconCls: 'fugue-disk-black',
            scope: this,
            handler: function() {
                if (this.checkValid()) {
                    this.doSave();
                    this.close();
                }
            }
        }));
        
        toolbar.add(new Ext.Button({
            text: this.closeText,
            iconCls: 'fugue-door-open-out',				
            scope: this,
            handler: function() {
                this.close();
            }
        }));
    },
	
    getFormPanelConfig: function() {
        var formPanelConfig = {			
            defaultType: 'textfield',				
            autoHeight: true,
            frame: true,
            labelWidth: 120,
            defaults: {
                anchor: '100%'
            },
            items: this.getFormPanelItems()					
        };
		
        return formPanelConfig;
    },
	
    getFormPanelItems: function() {
        var formPanelItemsConfig = [];
        
        if (this.accountEditMode == QFinance.component.TransactionEditWindow.editModes.BOTH || this.accountEditMode == QFinance.component.TransactionEditWindow.editModes.SOURCE) {
            formPanelItemsConfig.push(this.sourceComboBox = new Ext.form.ComboBox({
                fieldLabel: this.sourceAccountText,
                name: 'sourceAccountID',
                store: this.accountStore,
                typeAhead: true,
                triggerAction: 'all',
                emptyText: this.accountEmptyText,
                selectOnFocus: true,
                valueField: 'id',
                displayField: 'accountName',
                mode: 'local',
                forceSelection: true,
                value: null,
                readOnly: !this.canChangeSourceAccount
            }));
        }
		
        if (this.accountEditMode == QFinance.component.TransactionEditWindow.editModes.BOTH || this.accountEditMode == QFinance.component.TransactionEditWindow.editModes.DESTINATION) {
            formPanelItemsConfig.push(this.destinationComboBox = new Ext.form.ComboBox({
                fieldLabel: this.destinationAccountText,
                name: 'destinationAccountID',
                store: this.accountStore,
                typeAhead: true,
                triggerAction: 'all',
                emptyText: this.accountEmptyText,
                selectOnFocus: true,
                valueField: 'id',
                displayField: 'accountName',
                mode: 'local',
                forceSelection: true,
                value: null,
                readyOnly: !this.canChangeDestinationAccount
            }));
        } 
        
        return formPanelItemsConfig; 
    },
    
    doRefreshData: function() {
        this.accountStore.load();
    },
		
    checkValid: function() {
        var valid = true;
        var alertMessage
		
        if (!this.formPanel.getForm().isValid()) {
            valid = false;
            alertMessage = new QFinance.ui.MessageBox();
            alertMessage.show({
                title: this.formValidationTitleText,
                msg: this.fillRequiredFields,
                icon: alertMessage.WARNING,
                buttons: alertMessage.OK,
                renderTo: this.body
            });
        } else {
            if (this.requireCategory) {
                var selectedCategory = this.categoryPanel.getSelectedCategory();
                if (!selectedCategory) {
                    valid = false;
                    alertMessage = new QFinance.ui.MessageBox();
                    alertMessage.show({
                        title: this.formValidationTitleText,
                        msg: this.pleaseSelectAnCategory,
                        icon: alertMessage.WARNING,
                        buttons: alertMessage.OK,
                        renderTo: this.body
                    });
                }
            }
        }
		
        return valid;
    },
	
    doSave: function() {        
        Ext.each(this.records, function(record) {
            var selectedRecord;
            record.beginEdit();
            if (this.accountEditMode == QFinance.component.TransactionEditWindow.editModes.SOURCE) {
                if (!Ext.isEmpty(this.sourceComboBox.getValue())) { 
                    selectedRecord = this.accountStore.getAt( this.sourceComboBox.selectedIndex );
                    if (selectedRecord) {
                        record.set('sourceAccountID', selectedRecord.id);
                        record.set('sourceAccountName', selectedRecord.get('accountName'));
                    }	
                } else {
                    record.set('sourceAccountID', null);
                    record.set('sourceAccountName', null);
                }
            } else if (this.accountEditMode == QFinance.component.TransactionEditWindow.editModes.DESTINATION) {
                if (!Ext.isEmpty(this.destinationComboBox.getValue())) { 
                    selectedRecord = this.accountStore.getAt( this.destinationComboBox.selectedIndex );
                    if (selectedRecord) {
                        record.set('destinationAccountID', selectedRecord.id);
                        record.set('destinationAccountName', selectedRecord.get('accountName') );	
                    }
                } else {
                    record.set('destinationAccountID', null);
                    record.set('destinationAccountName', null );
                }
            }

            if (this.canChangeCategory) {
                var selectedCategory = this.categoryPanel.getSelectedCategory();
                if (selectedCategory) {
                    record.set('categoryID', selectedCategory.get('id'));
                    record.set('categoryName', selectedCategory.get('categoryName'));
                }
            }

            record.endEdit();		                        
        }, this);
        
        this.fireEvent('save', this.records);
    }	
});

QFinance.component.TransactionMultiEditWindow.editModes = {
    SOURCE: 'source',
    DESTINATION: 'destination',
    BOTH: 'both'
};

Ext.reg('QFinance.component.TransactionMultiEditWindow', QFinance.component.TransactionMultiEditWindow);
/*
 * @depends component.js, Window.js
 */
QFinance.component.TransactionEditWindow = Ext.extend( QFinance.ui.Window, {
    // Configuration
    isNew: true,
    canChangeDate: true,
    canChangeDescription: true,
    canChangeAmount: true,
    canChangeSourceAccount: true,
    canChangeDestinationAccount: true,
    canChangeCategory: true,
    accountEditMode: 'both',
    contextAccountID: null,	
    autoLoadRecord: true,
    record: null,
    requireCategory: true,
	
    // Localization
    saveText: 'Save',
    closeText: 'Close',
    idText: 'ID',
    dateText: 'Date',
    accountEmptyText: 'Select a account',
    sourceAccountText: 'Source account',
    destinationAccountText: 'Destination account',
    descriptionText: 'Description',
    bankMemoText: 'Bank memo',
    amountText: 'Amount',
    defaultTitleText: 'Edit transaction',
    editingTitleText: 'Editing transaction: {0}',
    pleaseSelectAnCategory: 'Please, select an category.',
    fillRequiredFields: 'Please, fill required fields.',
    removeTransactionTitleText: 'Drag and drop',
    removeTransactionText: 'Remove annotated transaction?',
    formValidationTitleText: 'Form validation',
    reloadDataText: 'Reload data',
    categoryText: 'Category',
    markText: 'Mark',
    markEmptyText: 'Select an mark',
			
    // Components
    accountStore: null,
    markStore: null,
    formPanel: null,
    categoryPanel: null,
    sourceComboBox: null,
    destinationComboBox: null,
    markComboBox: null,
    dropTarget: null,
	
    constructor: function(config) {
        Ext.apply(this,config);
		
        this.accountStore = new Ext.data.DirectStore({
            storeId: 'account-store',
            directFn: QFinance.Remoting.AccountAction.getAccountsMinus,
            paramsAsHash: false,
            idProperty: 'id',
            root: 'data',
            successProperty: 'success',
            paramOrder: [ 'excludeAccount' ],
            baseParams: {
                excludeAccount: this.contextAccountID
            },
            fields: [
            {
                name: 'id',
                type: 'int'
            },
            {
                name: 'accountName'	    		    
            },
            {
                name: 'accountType'
            }
            ],
            listeners: {
                scope: this,
                beforeload: function(store, options) {
                    var components = [];
                    if (this.sourceComboBox)
                        components.push(this.sourceComboBox);
                    if (this.destinationComboBox)
                        components.push(this.destinationComboBox);
                    store.id = this.getProcessStatusManager().start(components);
                    delete components;
                },				
                load: function(store, records, options) {
                    this.getProcessStatusManager().success(store.id);
                },			
                exception: function(dataProxy, type, action, options, response, arg ) {
                    var message = '';
                    var where = '';
                    if (response.result) {
                        message = response.result.message;
                        if (response.result.type == 'exception')
                            where = response.result.where;
                    } else {
                        message = response.message;
                    }
                    this.getProcessStatusManager().error(this.accountStore.id, message);                    
                    QFinance.service.DeveloperService.log('Store failure: ' + message + ' where\n' + where);
                }
            }		
        });

        this.markStore = new Ext.data.DirectStore({
            storeId: 'mark-store',
            directFn: QFinance.Remoting.TransactionEditWindowAction.getMarks,
            paramsAsHash: false,
            idProperty: 'id',
            root: 'data',
            successProperty: 'success',
            fields: [{
                name: 'id',
                type: 'int'
            },{
                name: 'name'	    		    
            }],
            listeners: {
                scope: this,
                beforeload: function(store, options) {
                    store.id = this.getProcessStatusManager().start([this.markComboBox]);
                },				
                load: function(store, records, options) {
                    this.getProcessStatusManager().success(store.id);
                },			
                exception: function(dataProxy, type, action, options, response, arg ) {
                    var message = '';
                    var where = '';
                    if (response.result) {
                        message = response.result.message;
                        if (response.result.type == 'exception')
                            where = response.result.where;
                    } else {
                        message = response.message;
                    }
                    this.getProcessStatusManager().error(this.markStore.id, message);                    
                    QFinance.service.DeveloperService.log('Store failure: ' + message + ' where\n' + where);
                }
            }		
        });
		
        this.addEvents(['save']);
		
        Ext.applyIf(this, {
            width: 400,
            height: 500
        });
		
        QFinance.component.TransactionEditWindow.superclass.constructor.call(this);
    },
	
    show: function() {		
        this.dropTarget = this.body;
        var me = this;
		
        var formPanelDropTarget = new Ext.dd.DropTarget(this.dropTarget, {
            ddGroup     : 'gridDDGroup',
            notifyDrop  : function(ddSource, e, data){
                var selectedRecord = ddSource.dragData.selections[0];
                var idField = me.formPanel.getForm().findField('id');
                var backupID = 0;				
				
                var removeTransactions = new QFinance.ui.MessageBox();
                removeTransactions.show({
                    title: me.removeTransactionTitleText,
                    msg: me.removeTransactionText,
                    buttons: Ext.Msg.YESNOCANCEL,				   
                    fn: function(btn, text, opt) {
                        if (btn == 'yes')
                            ddSource.grid.store.remove(selectedRecord);
                        else if (btn == 'cancel')
                            return (false);
					   
                        if (idField) {
                            backupID = idField.getValue();
                        }
						 
                        me.formPanel.getForm().loadRecord(selectedRecord);
						
                        if (idField) {
                            idField.setValue(backupID);
                        }
                        
                        return true;
                    },
                    renderTo: me.body,
                    animEl: 'elId',
                    icon: Ext.MessageBox.QUESTION
                });

                return(true);
            }
        }, this);
        QFinance.component.TransactionEditWindow.superclass.show.call(this);
						
        var dataLoadID = this.getProcessStatusManager().start([this]) 
        this.accountStore.load({
            scope: this,
            callback: function() {
                this.markStore.load({
                    scope: this,
                    callback: function() {
                        if (this.autoLoadRecord && this.record) {
                            this.loadRecord();
                        }                        
                        this.getProcessStatusManager().success(dataLoadID);
                    }
                })
            }
        });	
    },

    initComponent: function() {		
        var formPanelConfig = this.getFormPanelConfig();
        this.formPanel = new Ext.form.FormPanel(formPanelConfig);
						
        Ext.apply(this,{
            title: this.defaultTitleText,
            layout: 'vbox',
            bodyStyle:'padding: 5px',
            layoutConfig: {
                align : 'stretch',
                pack  : 'start'
            },	
            items: [ this.formPanel, {
                xtype: 'fieldset',
                title: this.categoryText,
                layout: 'fit',
                flex: 1,
                items: [ this.categoryPanel = new QFinance.component.CategoriesEditPanel({
                    disabled: !this.canChangeCategory,
                    autoSelectCategoryID: (this.record && this.record.get('categoryID') > 0) ? this.record.get('categoryID') : 'root',
                    ownerWindow: this
                })]
            }],
            tbar: [{
                text: this.reloadDataText,
                iconCls: 'fugue-arrow-circle',
                scope: this,
                handler: this.doRefreshData
            }]
        });		
		
        QFinance.component.TransactionEditWindow.superclass.initComponent.call(this);
    },
    
    initStatusBar: function(toolbar) {
        toolbar.add(new Ext.Button({
            text: this.saveText,
            iconCls: 'fugue-disk-black',
            scope: this,
            handler: function() {
                if (this.checkValid()) {
                    this.doSave();
                    this.close();
                }
            }
        }));
        
        toolbar.add(new Ext.Button({
            text: this.closeText,
            iconCls: 'fugue-door-open-out',				
            scope: this,
            handler: function() {
                this.close();
            }
        }));
    },
	
    getFormPanelConfig: function() {
        var formPanelConfig = {			
            defaultType: 'textfield',				
            autoHeight: true,
            frame: true,
            labelWidth: 120,
            defaults: {
                anchor: '100%'
            },
            items: this.getFormPanelItems()					
        };
		
        return formPanelConfig;
    },
	
    getFormPanelItems: function() {
        var formPanelItemsConfig = [];
		
        formPanelItemsConfig.push({
            fieldLabel: this.idText,
            name: 'id',
            readOnly: true
        });		
		
        formPanelItemsConfig.push({
            xtype: 'datefield',
            fieldLabel: this.dateText,
            name: 'date',
            format: QFinance.dateFormat,
            readOnly: !this.canChangeDate
        });
		
        if (this.accountEditMode == QFinance.component.TransactionEditWindow.editModes.BOTH || this.accountEditMode == QFinance.component.TransactionEditWindow.editModes.SOURCE) {
            formPanelItemsConfig.push(this.sourceComboBox = new Ext.form.ComboBox({
                fieldLabel: this.sourceAccountText,
                name: 'sourceAccountID',
                store: this.accountStore,
                typeAhead: true,
                triggerAction: 'all',
                emptyText: this.accountEmptyText,
                selectOnFocus: true,
                valueField: 'id',
                displayField: 'accountName',
                mode: 'local',
                forceSelection: true,
                value: null,
                readOnly: !this.canChangeSourceAccount
            }));
        }
		
        if (this.accountEditMode == QFinance.component.TransactionEditWindow.editModes.BOTH || this.accountEditMode == QFinance.component.TransactionEditWindow.editModes.DESTINATION) {
            formPanelItemsConfig.push(this.destinationComboBox = new Ext.form.ComboBox({
                fieldLabel: this.destinationAccountText,
                name: 'destinationAccountID',
                store: this.accountStore,
                typeAhead: true,
                triggerAction: 'all',
                emptyText: this.accountEmptyText,
                selectOnFocus: true,
                valueField: 'id',
                displayField: 'accountName',
                mode: 'local',
                forceSelection: true,
                value: null,
                readyOnly: !this.canChangeDestinationAccount
            }));
        } 

        formPanelItemsConfig.push( this.markComboBox = new Ext.form.ComboBox({            
            fieldLabel: this.markText,
            name: 'markID',
            store: this.markStore,
            typeAhead: true,
            triggerAction: 'all',
            emptyText: this.markEmptyText,
            selectOnFocus: true,
            valueField: 'id',
            displayField: 'name',
            mode: 'local',
            forceSelection: true,
            allowBlank: true,
            value: null
        }));
	
        formPanelItemsConfig.push({
            fieldLabel: this.descriptionText,
            name: 'description',
            readOnly: !this.canChangeDescription
        });
		
        formPanelItemsConfig.push({
            fieldLabel: this.bankMemoText,
            name: 'bankMemo',
            readOnly: true
        });
		
        formPanelItemsConfig.push({
            xtype: 'numberfield',
            fieldLabel: this.amountText,
            name: 'amount',
            readOnly: !this.canChangeAmount ,
            allowBlank: false,
            decimalSeparator: QFinance.decimalSeparator
        });
		
        return formPanelItemsConfig; 
    },    
        
    doRefreshData: function() {
        this.accountStore.load();
        this.markStore.load();
    },
	
    loadRecord: function() {
        var loadRecordID = this.getProcessStatusManager().start([this.formPanel]);
        if (!this.isNew)
            this.setTitle(String.format(this.editingTitleText,this.record.get('description') ? this.record.get('description') : this.record.get('bankMemo'))); 
        this.formPanel.getForm().loadRecord( this.record );
        this.getProcessStatusManager().success(loadRecordID);
    },
	
    checkValid: function() {
        var valid = true;
        var alertMessage
		
        if (!this.formPanel.getForm().isValid()) {
            valid = false;
            alertMessage = new QFinance.ui.MessageBox();
            alertMessage.show({
                title: this.formValidationTitleText,
                msg: this.fillRequiredFields,
                icon: alertMessage.WARNING,
                buttons: alertMessage.OK,
                renderTo: this.body
            });
        } else {
            if (this.requireCategory) {
                var selectedCategory = this.categoryPanel.getSelectedCategory();
                if (!selectedCategory) {
                    valid = false;
                    alertMessage = new QFinance.ui.MessageBox();
                    alertMessage.show({
                        title: this.formValidationTitleText,
                        msg: this.pleaseSelectAnCategory,
                        icon: alertMessage.WARNING,
                        buttons: alertMessage.OK,
                        renderTo: this.body
                    });
                }
            }
        }
		
        return valid;
    },
	
    doSave: function() {
        var selectedRecord;
        
        this.formPanel.getForm().updateRecord(this.record);		
        this.record.beginEdit();
		
        if (this.accountEditMode == QFinance.component.TransactionEditWindow.editModes.SOURCE || this.accountEditMode == QFinance.component.TransactionEditWindow.editModes.BOTH) {
            selectedRecord = this.accountStore.getById( this.sourceComboBox.getValue() );
            if (selectedRecord) {			
                this.record.set('sourceAccountName', selectedRecord.get('accountName'));
            } else {
                this.record.set('sourceAccountName', null);
            }
        } 
        if (this.accountEditMode == QFinance.component.TransactionEditWindow.editModes.DESTINATION || this.accountEditMode == QFinance.component.TransactionEditWindow.editModes.BOTH) {
            selectedRecord = this.accountStore.getById( this.destinationComboBox.getValue() );
            if (selectedRecord) {
                this.record.set('destinationAccountName', selectedRecord.get('accountName') );	
            } else {
                this.record.set('destinationAccountName', null );
            }
        } 
        
        selectedRecord = this.markStore.getById( this.markComboBox.getValue() );
        if (selectedRecord) {
            this.record.set('markName', selectedRecord.get('name') );	
        } else {
            this.record.set('markName', null );	
        }
		
        if (this.canChangeCategory) {
            var selectedCategory = this.categoryPanel.getSelectedCategory();
            if (selectedCategory) {
                this.record.set('categoryID', selectedCategory.get('id'));
                this.record.set('categoryName', selectedCategory.get('categoryName'));
            }
        }
		
        this.record.endEdit();		
		
        this.fireEvent('save', this.record);
    }	
});

QFinance.component.TransactionEditWindow.editModes = {
    SOURCE: 'source',
    DESTINATION: 'destination',
    BOTH: 'both'
};

Ext.reg('QFinance.component.TransactionEditWindow', QFinance.component.TransactionEditWindow);
/*
 * @depends component.js, Window.js
 */
QFinance.component.MarkEditWindow = Ext.extend( QFinance.ui.Window, {	
    // Configuration
    isNew: true,
    record: null,
    autoLoadRecord: false,
    savable: true,
	
    // Localization	
    defaultTitleText: 'Editing a new mark',
    editingTitleText: 'Editing mark: {0}',
    idText: 'ID',
    nameText: 'Name',
    descriptionText: 'Description',
    saveText: 'Save',
    closeText: 'Close',
    labelWidth: 65,
	
    // Components
    formPanel: null,
    
    constructor: function(config) {
        Ext.apply(this, config);
		
        this.title = this.defaultTitleText;
		
        Ext.applyIf(this, {
            width: 300,
            autoHeight: true
        });
		
        this.addEvents(['save']);
		
        QFinance.component.MarkEditWindow.superclass.constructor.call(this, config);
    },
	
    initComponent: function() {
        var formPanelConfig = this.getFormPanelConfig();
        this.formPanel = new Ext.form.FormPanel(formPanelConfig);		
				
        Ext.apply(this, {
            layout: 'fit',
            items: [this.formPanel]
        });	
		
        QFinance.component.MarkEditWindow.superclass.initComponent.call(this);		
    },
	
    show: function() {		
        QFinance.component.MarkEditWindow.superclass.show.call(this);

        if (this.autoLoadRecord && this.record)
            this.loadRecord();
    },
	
    initStatusBar: function( toolbar ) {        
        if (this.savable) {
            toolbar.add(new Ext.Button({
                text: this.saveText,
                formBind: true,
                scope: this,
                iconCls: 'fugue-disk-black',
                handler: function() {
                    if (this.formPanel.getForm().isValid()) {
                        this.doSave();	 
                        this.close();
                    }
                }
            }));
        }
				
        toolbar.add(new Ext.Button({
            text: this.closeText,
            iconCls: 'fugue-door-open-out',				
            scope: this,
            handler: function() {
                this.close();
            }
        }));
    },
	
    getFormPanelConfig: function() {
        var formPanelConfig = {
            frame: true,
            autoHeight: true,
            defaultType: 'textfield',
            defaults: {
                anchor: '100%'
            },
            labelWidth: this.labelWidth,
            items: this.getFormPanelItems()
        };
		
        return formPanelConfig;
    },
	
    getFormPanelItems: function() {
        var formPanelItems = [{
            xtype: 'displayfield',
            fieldLabel: this.idText,
            name: 'id'
        },{
            fieldLabel: this.nameText,
            name: 'name',    		
            allowBlank: false
        },{
            fieldLabel: this.descriptionText,
            name: 'description',
            allowBlank: true
        }];
		
        return formPanelItems;
    },
	
    doSave: function() {        
        this.formPanel.getForm().updateRecord( this.record );		
        this.fireEvent('save', this.record);
    },	
	
    loadRecord: function() {
        if (!this.isNew)
            this.setTitle(String.format(this.editingTitleText, this.record.get('name')));
        this.formPanel.getForm().loadRecord( this.record );
    }
});
Ext.reg('QFinance.component.MarkEditWindow', QFinance.component.MarkEditWindow);
/*
 * @depends component.js, Window.js
 */
QFinance.component.CategoryEditWindow = Ext.extend( QFinance.ui.Window, {
    // Configuration
    isNew: true,
    record: null,
    autoLoadRecord: false,
    canChangeID: false,
    canChangeCategoryName: true,
    savable: true,
	
    // Localization
    defaultTitleText: 'Editing a new category',
    editingTitleText: 'Editing category: {0}',
    idText: 'ID',
    categoyNameText: 'Name',
    saveText: 'Save',
    closeText: 'Close',
	
    // Components
    formPanel: null,

    constructor: function(config) {
        Ext.apply(this, config);
		
        this.title = this.defaultTitleText;
		
        Ext.applyIf(this, {
            width: 200,
            autoHeight: true
        });
		
        this.addEvents(['save']);
		
        QFinance.component.CategoryEditWindow.superclass.constructor.call(this);
    },
	
    initComponent: function() {
        var formPanelConfig = this.getFormPanelConfig();
        this.formPanel = new Ext.form.FormPanel(formPanelConfig);
						
        Ext.apply(this, {
            layout: 'fit',
            items: [this.formPanel],
            bbar: this.statusBar
        });	
		
        if (this.autoLoadRecord && this.record)
            this.loadRecord();
		
        QFinance.component.CategoryEditWindow.superclass.initComponent.call(this);
    },
	
    initStatusBar: function(toolbar) {		
        if (this.savable) {
            toolbar.add(new Ext.Button({
                text: this.saveText,
                formBind: true,
                scope: this,
                iconCls: 'fugue-disk-black',
                handler: function() {
                    if (this.formPanel.getForm().isValid()) {
                        this.doSave();	 
                        this.close();
                    }
                }
            }));
        }
				
        toolbar.add(new Ext.Button({
            text: this.closeText,
            iconCls: 'fugue-door-open-out',				
            scope: this,
            handler: function() {
                this.close();
            }
        }));	
    },
	
    getFormPanelConfig: function() {
        var formPanelConfig = {
            frame: true,
            autoHeight: true,
            defaultType: 'textfield',
            defaults: {
                anchor: '100%'
            },
            labelWidth: 50,
            items: this.getFormPanelItems()
        };
		
        return formPanelConfig;
    },
	
    getFormPanelItems: function() {
        var formPanelItems = [{
            fieldLabel: this.idText,
            name: 'id',
            readOnly: !this.canChangeID,
            width: 40
        },
        {
            fieldLabel: this.categoyNameText,
            name: 'categoryName',
            readyOnly: !this.canChangeCategoryName,
            allowBlank: false
        }];
		
        return formPanelItems;
    },
	
    doSave: function() {
        this.formPanel.getForm().updateRecord( this.record );		
        this.fireEvent('save', this.record);
    },	
	
    loadRecord: function() {
        if (!this.isNew)
            this.setTitle(String.format(this.editingTitleText, this.record.get('categoryName')));
        this.formPanel.getForm().loadRecord( this.record );
    }
});
Ext.reg('QFinance.component.CategoryEditWindow', QFinance.component.CategoryEditWindow);
/*
 * @depends component.js, Window.js
 */
QFinance.component.AccountEditWindow = Ext.extend( QFinance.ui.Window, {	
    // Configuration
    isNew: true,
    record: null,
    autoLoadRecord: false,
    savable: true,
	
    // Localization	
    defaultTitleText: 'Editing a new account',
    editingTitleText: 'Editing account: {0}',
    idText: 'ID',
    accountNameText: 'Account name',
    bankNumberText: 'Bank number',
    bankAgencyText: 'Bank agency',
    bankAccountText: 'Bank account',
    initialAmountText: 'Initial amount',
    accountTypeText: 'Type',
    accountTypeEmptyText: 'Select a type',
    saveText: 'Save',
    closeText: 'Close',
    privateText: 'Private',
    publicText: 'Public',
    labelWidth: 90,
	
    // Components
    formPanel: null,
    accountTypeCombo: null,

    constructor: function(config) {
        Ext.apply(this, config);
		
        this.title = this.defaultTitleText;
		
        Ext.applyIf(this, {
            width: 300,
            autoHeight: true
        });
		
        this.addEvents(['save']);
		
        QFinance.component.AccountEditWindow.superclass.constructor.call(this, config);
    },
	
    initComponent: function() {
        var formPanelConfig = this.getFormPanelConfig();
        this.formPanel = new Ext.form.FormPanel(formPanelConfig);		
				
        Ext.apply(this, {
            layout: 'fit',
            items: [this.formPanel]
        });	
		
        QFinance.component.AccountEditWindow.superclass.initComponent.call(this);		
    },
	
    show: function() {		
        QFinance.component.AccountEditWindow.superclass.show.call(this);

        if (this.autoLoadRecord && this.record)
            this.loadRecord();
    },
	
    initStatusBar: function( toolbar ) {        
        if (this.savable) {
            toolbar.add(new Ext.Button({
                text: this.saveText,
                formBind: true,
                scope: this,
                iconCls: 'fugue-disk-black',
                handler: function() {
                    if (this.formPanel.getForm().isValid()) {
                        this.doSave();	 
                        this.close();
                    }
                }
            }));
        }
				
        toolbar.add(new Ext.Button({
            text: this.closeText,
            iconCls: 'fugue-door-open-out',				
            scope: this,
            handler: function() {
                this.close();
            }
        }));
    },
	
    getFormPanelConfig: function() {
        var formPanelConfig = {
            frame: true,
            autoHeight: true,
            defaultType: 'textfield',
            defaults: {
                anchor: '100%'
            },
            labelWidth: this.labelWidth,
            items: this.getFormPanelItems()
        };
		
        return formPanelConfig;
    },
	
    getFormPanelItems: function() {
        var formPanelItems = [{
            fieldLabel: this.idText,
            name: 'id',
            readOnly: true
        },{
            fieldLabel: this.accountNameText,
            name: 'accountName',    		
            allowBlank: false
        },{
            fieldLabel: this.bankNumberText,
            name: 'bankNumber',
            allowBlank: true
        },{
            fieldLabel: this.bankAgencyText,
            name: 'bankAgency',
            allowBlank: true    		
        },{
            fieldLabel: this.bankAccountText,
            name: 'bankAccount',
            allowBlank: true
        },{
            xtype: 'numberfield',
            fieldLabel: this.initialAmountText,
            name: 'initialAmount',
            allowBlank: false,
            decimalSeparator: QFinance.decimalSeparator,
            value: 0
        },
        this.accountTypeCombo = new Ext.form.ComboBox({
            fieldLabel: this.accountTypeText,
            name: 'accountType',    		
            typeAhead: true,
            triggerAction: 'all',
            emptyText: this.accountTypeEmptyText,
            selectOnFocus: true,
            forceSelection: true,
            allowBlank: false,
            store: [
            ['1', this.privateText],
            ['2', this.publicText]
            ]    	     
        })];
		
        return formPanelItems;
    },
	
    doSave: function() {
        this.record.set('accountTypeName', this.accountTypeCombo.getRawValue());
        this.formPanel.getForm().updateRecord( this.record );		
        this.fireEvent('save', this.record);
    },	
	
    loadRecord: function() {
        if (!this.isNew)
            this.setTitle(String.format(this.editingTitleText, this.record.get('accountName')));
        this.formPanel.getForm().loadRecord( this.record );
    }
});
Ext.reg('QFinance.component.AccountEditWindow', QFinance.component.AccountEditWindow);
/*
 * @depends ui.js, Panel.js
 */
QFinance.ui.WizardPanel = Ext.extend( QFinance.ui.Panel, {
    // Localization
    navigatorNextText: 'Next',
    navigatorPreviousText: 'Previous',
    navigatorFinishText: 'Finish',
	
    // Navigator bar items
    previousButton: null,
    nextButton: null,
    finishButton: null,
    activeItem: 0,
		
    constructor: function(config) {
        Ext.apply(this, config);
		
        this.addEvents([ 
            'beforeitemchange',
            'itemchange',
            'beforefinish',
            'finish'
            ]);		
        QFinance.ui.WizardPanel.superclass.constructor.call(this);
    },
	
    initComponent: function() {
        Ext.apply(this, {
            layout: 'card',			
            items: []
        });
		
        QFinance.ui.WizardPanel.superclass.initComponent.call(this);
    },

    initStatusBar: function(toolbar) {
        toolbar.insert(0,this.finishButton = new Ext.Button({
            text: this.navigatorFinishText,
            disabled: true,
            scope: this,
            handler: this.finish,
            iconCls: 'fugue-flag-black'
        }));
		
        toolbar.insert(0,this.nextButton =new Ext.Button({
            text: this.navigatorNextText,
            scope: this,
            handler: this.next,
            iconAlign: 'right',
            iconCls: 'fugue-arrow'
        }));
		
        toolbar.insert(0,this.previousButton = new Ext.Button({
            text: this.navigatorPreviousText,
            disabled: true,
            scope: this,
            handler: this.previous,
            iconCls: 'fugue-arrow-180'
        }));
    },
		
    previous: function() {
        if (this.activeItem > 0)
            this.activateItem(this.activeItem - 1);
    },
	
    next: function() {
        if (this.activeItem < this.items.getCount())
            this.activateItem(this.activeItem + 1);
    },
	
    finish: function() {
        if (this.fireEvent('beforefinish', this) !== false)
            this.fireEvent('finish', this);
    },

    activateItem: function( index ) {
        if (this.fireEvent('beforeitemchange', this, this.items.get(this.activeItem), this.items.get(index)) !== false) {
            var fromIndex = this.activeItem;
            this.previousButton.setDisabled(index == 0);
            this.nextButton.setDisabled(index == (this.items.getCount() - 1));
            this.finishButton.setDisabled(index != (this.items.getCount() - 1));
            this.getLayout().setActiveItem(index);
            this.activeItem = index;
            this.fireEvent('itemchange', this, this.items.get(fromIndex), this.items.get(index));
        }
    }
});
Ext.reg('QFinance.ui.WizardPanel', QFinance.ui.WizardPanel);
/*
 * @depends *
 */
QFinance.App = Ext.extend(Ext.util.Observable, {
    isReady: false,
    startMenu: null,
    modules: null,    
    bypassLogin: false,
    
    // Localization
    usersText: 'Users',
    settingsText: 'Settings',
    logoutText: 'Logout',
    menuWidth: 350,
    
    constructor: function(cfg) {
        Ext.apply(this, cfg);
        this.addEvents({
            'ready' : true,
            'beforeunload' : true
        });
        QFinance.App.superclass.constructor.call(this);
    },

    // config for the start menu
    getStartConfig : function(){
        return {
            title: 'QFinance',
            iconCls: 'fugue-user',  
            width: this.menuWidth,
            toolItems: [{
                text: this.usersText,
                iconCls: 'fugue-users',
                scope: this,
                handler: function() {
                    var module = new QFinance.module.UsersModule();
                    module.setApp(this);
                    module.createWindow();
                }
            },{
                text: this.settingsText,
                iconCls: 'fugue-gear',
                scope: this,
                handler: function() {
                    Ext.Msg.alert('Alert', 'Not implemented yet!.');
                }
            },"-",{
                text: this.logoutText,
                iconCls: 'fugue-key',
                scope: this,
                handler: this.logout
            }]
        };
    },

    initApp : function(){
        var init = function() {
            this.startConfig = this.startConfig || this.getStartConfig();			
						
            this.desktop = new Ext.Desktop(this);
	
            this.launcher = this.desktop.taskbar.startMenu;
	
            this.modules = this.getModules();
            if(this.modules)
                this.initModules(this.modules);
	
            this.init();
	        
            this.initPortal();
	
            Ext.EventManager.on(window, 'beforeunload', this.onUnload, this);
            this.fireEvent('ready', this);
            this.isReady = true;
        };
		
        this.configure(function() {
            if (!QFinance.service.DeveloperService.bypassLogin) {
                var loginWindow = new QFinance.LoginWindow( {
                    listeners: {
                        scope: this,
                        logged : init 
                    }
                });
                loginWindow.show();
            } else {
                init.call(this);
            }	
        }, this);
    },

    getModules : function(){
        return [
        new QFinance.module.OverviewModule(),
        new QFinance.module.TransactionsModule(),
        new QFinance.module.AnnotatedTransactionsModule(),
        new QFinance.module.AccountsModule(),
        new QFinance.module.CategoriesModule(),
        new QFinance.module.MarksModule(),
        new QFinance.module.TransactionsImportModule(),
        new QFinance.module.ReportsModule(),
        new QFinance.module.TestModule(),
        new QFinance.module.DeveloperConsoleModule()
        ];
    },
    init : Ext.emptyFn,

    initModules : function(ms){
        for(var i = 0, len = ms.length; i < len; i++){
            var m = ms[i];
            this.launcher.add(m.launcher);
            m.setApp(this);
        }
    },

    getModule : function(name){
        var ms = this.modules;
        for(var i = 0, len = ms.length; i < len; i++){
            if(ms[i].id == name || ms[i].appType == name){
                return ms[i];
            }
        }
        return '';
    },

    onReady : function(fn, scope){
        if(!this.isReady){
            this.on('ready', fn, scope);
        }else{
            fn.call(scope, this);
        }
    },

    getDesktop : function(){
        return this.desktop;
    },

    onUnload : function(e){
        if(this.fireEvent('beforeunload', this) === false){
            e.stopEvent();
        }
    },
    
    configure : function(callback, scope) {
        Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
        Ext.QuickTips.init();		
        Ext.Direct.on('event', function(e, provider) {
            if (e.action != 'DeveloperServiceAction')
                QFinance.service.DeveloperService.log('Called action: \'' + e.action + '\' method: \'' + e.method + '\'');
        });
        QFinance.service.DeveloperService.load(function() {
            if (callback) callback.call(scope||this);
        },this);
    },
    
    logout: function() {
        QFinance.Remoting.LoginAction.logout(function(result, event) {
            var message = '';
            var where = '';
            var failure = false;
    		
            if (result) {
                if (result.success) {
                    window.location.reload();		
                } else {
                    failure = true;						
                    message = result.message;
                    if (result.type == 'exception')
                        where = result.where;
                }            
            } else {
                failure = true;
                message = event.message;
            }
    		
            if (failure) {	
                QFinance.service.DeveloperService.log('Direct call failure: ' + message + ' where\n' + where);
                Ext.Msg.alert('Logout', message);
            }

        }, this);
    },
    
    initPortal: function() {
    	
    	
       
    }
});
/*
 * @depends *
 */
// Prevent combobox z-indez when in nested window
Ext.override(Ext.form.ComboBox, {
    getParentZIndex : function(){
        var zindex = 0;
        if (this.ownerCt){
            this.findParentBy(function(ct){
                zindex = Math.max(zindex, parseInt(ct.getPositionEl().getStyle('z-index'), 10));
                //return !!zindex;
            });
        }
        return zindex;
    }
});

// Prevent combo getValue behavior
Ext.override(Ext.form.BasicForm, {
	updateRecord : function(record){	
	    record.beginEdit();
	    var fs = record.fields,
	        field,
	        value;
	    fs.each(function(f){
	        field = this.findField(f.name);
	        if(field){
	            value = field.getValue();
	            if (value && typeof value != undefined && value.getGroupValue) {
	                value = value.getGroupValue();
	            } else if ( field.eachItem ) {
	                value = [];
	                field.eachItem(function(item){
	                    value.push(item.getValue());
	                });
	            } else if ( typeof field.selectedIndex != undefined && Ext.isEmpty(value) ) {
	            	value = null;
	            }
	            record.set(f.name, value);
	        }
	    }, this);
	    record.endEdit();
	    return this;
	}
});

// Normalize exception behavior of DirectProxy
Ext.override(Ext.data.DirectProxy, {
	/**
     * Callback for read actions
     * @param {String} action [Ext.data.Api.actions.create|read|update|destroy]
     * @param {Object} trans The request transaction object
     * @param {Object} result Data object picked out of the server-response.
     * @param {Object} res The server response
     * @protected
     */
    onRead : function(action, trans, result, res) {
        var success = trans.reader.getSuccess(result);
        if (success) {
	        var records = trans.reader.readRecords(result);
	        this.fireEvent("load", this, res, trans.request.arg);
	        trans.request.callback.call(trans.request.scope, records, trans.request.arg, true);
        } else {
            // @deprecated: Fire old loadexception for backwards-compat.
            this.fireEvent("loadexception", this, trans, res);

            this.fireEvent('exception', this, 'response', action, trans, res);
            trans.request.callback.call(trans.request.scope, null, trans.request.arg, false);
            return;
        }
    },
	/**
	 * Callback for write actions
	 * @param {String} action [{@link Ext.data.Api#actions create|read|update|destroy}]
	 * @param {Object} trans The request transaction object
	 * @param {Object} result Data object picked out of the server-response.
	 * @param {Object} res The server response
	 * @param {Ext.data.Record/[Ext.data.Record]} rs The Store resultset associated with the action.
	 * @protected
	 */
	onWrite : function(action, trans, result, res, rs) {
        var success = trans.reader.getSuccess(result);
        if (success) {
			var data = trans.reader.extractData(trans.reader.getRoot(result), false);
			this.fireEvent("write", this, action, data, res, rs, trans.request.arg);
			trans.request.callback.call(trans.request.scope, data, res, true);
        } else {
        	// @deprecated: Fire old loadexception for backwards-compat.
	        this.fireEvent("loadexception", this, trans, res);

	        this.fireEvent('exception', this, 'remote', action, trans, res);
	        trans.request.callback.call(trans.request.scope, null, trans.request.arg, false);
        }
	}
});

//Add silent (don't focus) node selection.
Ext.override(Ext.tree.TreeNodeUI, {
    onSilentSelectedChange : function(state){
        if(state){
        	this.focusSilent();
            this.addClass("x-tree-selected");
        }else{            
            this.removeClass("x-tree-selected");
        }
    },
    
    // private
    focusSilent : function(){
        if(!this.node.preventHScroll){
            try{this.anchor.scrollIntoViewIfNeeded();
            }catch(e){}
        }else{
            try{
                var noscroll = this.node.getOwnerTree().getTreeEl().dom;
                var l = noscroll.scrollLeft;
                this.anchor.scrollIntoViewIfNeeded();
                noscroll.scrollLeft = l;
            }catch(e){}
        }
    }
});

//Add silent (don't focus) node selection.
Ext.override(Ext.tree.DefaultSelectionModel, {
	   /**
     * Select a node.
     * @param {TreeNode} node The node to select
     * @return {TreeNode} The selected node
     */
    selectSilent : function(node, /* private*/ selectNextNode){
        // If node is hidden, select the next node in whatever direction was being moved in.
        if (!Ext.fly(node.ui.wrap).isVisible() && selectNextNode) {
            return selectNextNode.call(this, node);
        }
        var last = this.selNode;
        if(node == last){
            node.ui.onSilentSelectedChange(true);
        }else if(this.fireEvent('beforeselect', this, node, last) !== false){
            if(last && last.ui){
                last.ui.onSilentSelectedChange(false);
            }
            this.selNode = node;
            node.ui.onSilentSelectedChange(true);
            this.fireEvent('selectionchange', this, node, last);
        }
        return node;
    }
});

// Add silent (don't focus) node selection.
Ext.override(Ext.tree.TreeNode, {
	/*
    * Triggers selection of this node
    */
   selectSilent : function(){
       var t = this.getOwnerTree();
       if(t){
           t.getSelectionModel().selectSilent(this);
       }
   }
});

// Prevent child window 'maxime' problem. 
Ext.override(Ext.Window, {
	   /**
     * Fits the window within its current container and automatically replaces
     * the {@link #maximizable 'maximize' tool button} with the 'restore' tool button.
     * Also see {@link #toggleMaximize}.
     * @return {Ext.Window} this
     */
    maximize : function(){
        if(!this.maximized){
            this.expand(false);
            this.restoreSize = this.getSize();
            this.restorePos = this.getPosition(true);
            if (this.maximizable){
                this.tools.maximize.hide();
                this.tools.restore.show();
            }
            this.maximized = true;
            this.el.disableShadow();

            if(this.dd){
                this.dd.lock();
            }
            if(this.collapsible){
                this.tools.toggle.hide();
            }
            //this.el.addClass('x-window-maximized');
            //this.container.addClass('x-window-maximized-ct');

            this.setPosition(0, 0);
            this.fitContainer();
            this.fireEvent('maximize', this);
        }
        return this;
    },

    /**
     * Restores a {@link #maximizable maximized}  window back to its original
     * size and position prior to being maximized and also replaces
     * the 'restore' tool button with the 'maximize' tool button.
     * Also see {@link #toggleMaximize}.
     * @return {Ext.Window} this
     */
    restore : function(){
        if(this.maximized){
            var t = this.tools;
            //this.el.removeClass('x-window-maximized');
            if(t.restore){
                t.restore.hide();
            }
            if(t.maximize){
                t.maximize.show();
            }
            this.setPosition(this.restorePos[0], this.restorePos[1]);
            this.setSize(this.restoreSize.width, this.restoreSize.height);
            delete this.restorePos;
            delete this.restoreSize;
            this.maximized = false;
            this.el.enableShadow(true);

            if(this.dd){
                this.dd.unlock();
            }
            if(this.collapsible && t.toggle){
                t.toggle.show();
            }
            //this.container.removeClass('x-window-maximized-ct');

            this.doConstrain();
            this.fireEvent('restore', this);
        }
        return this;
    }
});

Ext.apply(Ext.form.VTypes, {
    daterangecomposite : function(val, field) {
        var date = field.parseDate(val);
 
        if (!date)
            return false;

        if (field.startDateField && (!this.dateRangeMax || (date.getTime() != this.dateRangeMax.getTime()))) {			
            var start = Ext.getCmp(field.startDateField);
            start.setMaxValue(date);
            start.validate();
            this.dateRangeMax = date;
        } 
        else if (field.endDateField && (!this.dateRangeMin || (date.getTime() != this.dateRangeMin.getTime()))) {			
            var end = Ext.getCmp(field.endDateField);
            end.setMinValue(date);
            end.validate();
            this.dateRangeMin = date;
        }
        /*
         * Always return true since we're only using this vtype to set the
         * min/max allowed values (these are tested for after the vtype test)
         */
        return true;
    },
    
    // Password Check
    passwordText: 'The passwords entered do not match.',
    password: function(value, field) {
        var valid = false;
        if (field.matches) {
            var otherField = Ext.getCmp(field.matches);
            if (value == otherField.getValue()) {
                otherField.clearInvalid();
                valid = true;
            }
        }
        return valid;
    }
});
